diff --git a/.codex/skills/write-oliphaunt-docs/SKILL.md b/.codex/skills/write-oliphaunt-docs/SKILL.md
new file mode 100644
index 000000000..addd62818
--- /dev/null
+++ b/.codex/skills/write-oliphaunt-docs/SKILL.md
@@ -0,0 +1,48 @@
+---
+name: write-oliphaunt-docs
+description: Write, rewrite, audit, or redesign Oliphaunt developer documentation. Ground polyglot SDK examples and behavior in implementation, keep generated reference data synchronized, and verify the rendered Fumadocs site. Use for public docs and SDK READMEs, not release operations or historical architecture records.
+---
+
+# Write Oliphaunt docs
+
+Help a developer choose an SDK, run a query, and ship a working integration. Use this workflow for the requested scope; a small correction does not need a whole-site audit.
+
+## Establish the facts
+
+- Read the affected pages completely, then follow the exported API through its implementation and focused tests. Existing prose is a claim to verify, not authority.
+- Use [source-map.md](references/source-map.md) to locate SDK contracts, generated inputs, and checks. Inspect the current files; the map is a starting point, not a frozen API specification.
+- Distinguish implemented behavior, released package availability, and future intent. Repository version metadata alone does not prove registry publication. Browse primary sources when documenting external installation requirements or current releases.
+- For a rewrite, inventory every authored page and generated route. Record each file's purpose, accuracy findings, source evidence, and disposition in a maintainer audit under `src/docs/maintainers/`. Preserve useful behavior details when removing noise. Keep historical design records outside the public navigation.
+- Resolve uncertain behavior before presenting it as fact. Put remaining uncertainty and unrun checks in the audit or handoff, never in public TODOs, speculative promises, or invented output.
+
+## Organize around the developer's task
+
+Use [research.md](references/research.md) when changing information architecture or the authoring workflow. Its recommendations are adaptations of inspected primary sources, not instructions to install other projects' skills or services.
+
+- Start: explain the product in a short paragraph, help choose language/runtime, and lead directly to a first query.
+- SDK quickstart: requirements → install → complete first query → expected result → persistence → next task. Show the code early. Include imports, required setup, parameter binding, and cleanup.
+- SDK guide: recipes for persistent storage, transactions, backup/restore, extensions, errors, and shutdown where supported. Link the quickstart instead of repeating it.
+- API reference: exported entry points, options/defaults, parameter and return types, errors, and lifecycle constraints. Use implementation-derived declarations when available; edit generator inputs rather than generated output.
+- Shared guides: explain common concepts once. Keep language-specific differences next to the affected example. Do not imply that shared PostgreSQL semantics mean identical SDK APIs, concurrency, storage, or runtime support.
+- Prefer one coherent sidebar and shallow groups. Confirm that new pages are actually navigable and searchable. Preserve URLs where possible and verify changed anchors and incoming links.
+
+## Write and build
+
+- Use direct sentences, sentence-case headings, descriptive links, and language-tagged code fences. Begin sections with the information needed to act. Remove marketing claims, repeated summaries, maintainer commands, release-pipeline details, and implementation vocabulary that does not affect an integration decision.
+- Use `{{release:product-id}}` for public install and release versions. Generation maps product IDs through `release-please-config.json` to `.release-please-manifest.json`, pairing examples with the checkout API. Keep completed GitHub releases separate; an older published package must never relabel a newer API example. Preserve the build's `docs-version.json` when archiving it. Do not invent a shared SDK version or hosted historical versions. See the [docs README](../../../src/docs/README.md).
+- Apply the `better-writing` skill for prose reviews: put the developer's action first, remove internal design explanations, and make prerequisites explicit before the first runnable example.
+- Make examples idiomatic for each language. Verify names, overloads, imports, ownership, async behavior, storage types, package coordinates, and failure handling separately for every SDK. Do not translate examples mechanically.
+- Explain prerequisites before commands. Distinguish a complete program from a fragment that uses an existing `db`. Show expected output only when supported by execution or an unambiguous deterministic expression.
+- Keep warnings next to actions that can lose data or block an integration. Do not hide mandatory steps in tabs or disclosures. Use tabs only for interchangeable choices, such as package managers.
+- Reuse Fumadocs and its accessible primitives before adding components or dependencies. Use the available `better-interface` skills for layout, writing, typography, color, UI, and accessibility; use the React/Next.js skills when changing site code.
+- Follow the [design grounding](../../../src/docs/DESIGN_GROUNDING.md) for the site's dark default, constrained typography, spacing, and illustration style. Keep decorative artwork in the site shell rather than the exported developer instructions.
+
+## Verify the actual result
+
+1. Check the source-backed claims and example assumptions again after editing. A snippet marker, keyword match, successful MDX build, or AI review is not evidence that the example runs.
+2. Run the existing docs checks from [source-map.md](references/source-map.md). When changing a checker, retain route, metadata, link, release-data, and API invariants; replace obsolete prose/design assertions with checks of observable behavior. Do not weaken a real check just to make a rewrite pass.
+3. Execute representative complete examples against temporary databases using available runtimes. Type-check other changed examples where possible. Record each SDK as executed, compiled/type-checked, source-reviewed, or blocked with a concrete reason. Never describe source review as execution. Keep backups/restores isolated from user data.
+4. For UI work, inspect actual browser screenshots on desktop and narrow mobile, in light and dark themes. Check navigation, search, keyboard focus, code copying, tabs, long tables, and horizontal overflow. Correct defects and inspect the affected screen again. Use existing browser tools; do not add a second UI stack for review.
+5. Read as a newcomer using only the rendered docs: Which package fits my app? What do I install? Where does the code run? What result do I get? How do I keep data, handle failures, and close the database? Missing answers are docs defects. For lookup pages, test whether a reader can locate a specific option or method directly.
+
+Finish with the changed scope, checks that actually ran, and material limitations. Follow the user's existing authorization; this skill adds no permission or publishing workflow.
diff --git a/.codex/skills/write-oliphaunt-docs/agents/openai.yaml b/.codex/skills/write-oliphaunt-docs/agents/openai.yaml
new file mode 100644
index 000000000..d153236ec
--- /dev/null
+++ b/.codex/skills/write-oliphaunt-docs/agents/openai.yaml
@@ -0,0 +1,4 @@
+interface:
+ display_name: "Write Oliphaunt docs"
+ short_description: "Source-grounded SDK docs and visual review"
+ default_prompt: "Use $write-oliphaunt-docs to improve Oliphaunt developer docs, verify examples against the SDKs, and review the rendered site."
diff --git a/.codex/skills/write-oliphaunt-docs/references/research.md b/.codex/skills/write-oliphaunt-docs/references/research.md
new file mode 100644
index 000000000..81487fa38
--- /dev/null
+++ b/.codex/skills/write-oliphaunt-docs/references/research.md
@@ -0,0 +1,62 @@
+# Research: AI-assisted developer documentation
+
+Inspected 2026-09-08. These are primary project instructions, implementations, product documentation, and one empirical paper. They describe observable workflows; they do not establish that AI-generated prose is accurate or that a particular tool improves productivity. GitHub links track their named branches and may change.
+
+## How projects use AI to write and maintain docs
+
+| Inspected source | Observed practice | Adaptation for Oliphaunt |
+| --- | --- | --- |
+| [Supabase authoring guide](https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md) | Ships separate agent skills for planning, architecture, drafting, editing, execution, and review. Defines four document types and sources reference parameters from code. | Keep the stages distinct within one small local skill; avoid a network of skills for a site this size. |
+| [Supabase write-the-docs](https://github.com/supabase/supabase/blob/master/.agents/skills/write-the-docs/SKILL.md) | Reads product intent and implementation before drafting, distinguishes generated reference from authored guides, wires navigation, and removes internal planning notes. | Code establishes behavior; the user's request establishes the rewrite's purpose. Explicitly track source uncertainty outside public pages. |
+| [Supabase test-the-docs](https://github.com/supabase/supabase/blob/master/.agents/skills/test-the-docs/SKILL.md) | Classifies complete examples, setup-dependent snippets, illustrative fragments, and deferred checks; executes in disposable environments and reports results. | Run Oliphaunt examples on temporary roots. Record execution versus type-checking versus source review per SDK. Its Supabase Docker stack is not applicable here. |
+| [Supabase edit-the-docs](https://github.com/supabase/supabase/blob/master/.agents/skills/edit-the-docs/SKILL.md) | Gives existing-page restructuring its own workflow, separate from inventing a new product story. | Preserve useful integration facts while rebuilding hierarchy and prose. A rewrite is not permission to infer capabilities. |
+| [Next.js update-docs skill](https://github.com/vercel/next.js/blob/canary/.agents/skills/update-docs/SKILL.md) | Maps source changes to docs locations, checks existing coverage, and handles shared content and examples. | Maintain a local source map; search all affected SDK pages when a common contract changes. Do not copy Next.js-specific paths or per-edit approval steps. |
+| [Cloudflare agent instructions](https://github.com/cloudflare/cloudflare-docs/blob/production/AGENTS.md) and [agent style reference](https://github.com/cloudflare/cloudflare-docs/blob/production/.agents/references/style-guide.md) | Give agents the real content pipeline, component rules, validation commands, and a distilled reference linked to the authoritative style guide. | Put stable workflow in `SKILL.md`, repository details in a linked source map, and reuse the installed UI skills. |
+| [Cloudflare docs review bot](https://github.com/cloudflare/cloudflare-docs/blob/production/.flue/AGENTS.md) | Separates code, conventions, and style review; validates findings against repository context. Structured results feed controlled publishing code. | Review correctness, discoverability, and writing separately. Require source evidence for findings. A bot service and automatic publishing are unnecessary for this rewrite. |
+| [GitHub documentation-writer skill](https://github.com/github/awesome-copilot/blob/main/skills/documentation-writer/SKILL.md) | Uses reader goals and Diátaxis to distinguish tutorials, guides, reference, and explanations. | Give each page a clear job, rather than adding the same summary and reference block everywhere. |
+| [GitHub docs-sync-audit skill](https://github.com/github/awesome-copilot/blob/main/skills/docs-sync-audit/SKILL.md) | Compares docs with code, reports drift with evidence, distinguishes confirmed findings from inference, and records checks not run. | Keep a file-by-file audit. Check generated sources and all plausible locations before declaring information missing. Its read-only scope does not apply to an authorized rewrite. |
+| [Anthropic doc-coauthoring skill](https://github.com/anthropics/skills/blob/main/skills/doc-coauthoring/SKILL.md) | Gathers context, iterates on structure, and tests whether a reader without prior context can answer likely questions. | Perform a newcomer task review from the rendered docs. Its interview-heavy process is excessive when source and task intent are already available. |
+| [Mintlify authoring skill](https://github.com/mintlify/docs/blob/main/skill.md) | Describes navigation, MDX components, concise writing, examples, and validation for its documentation framework. | Prefer shallow navigation, concrete prerequisites, and sparse callouts. Use Fumadocs APIs here; do not import Mintlify syntax or leave uncertainty as public TODOs. |
+| [Mintlify agent](https://www.mintlify.com/docs/agent) | Searches docs, connected code, and web context; plans, edits, validates, and submits changes according to configured review settings. | Adopt research → source-grounded edits → validation. A subscription or connector is not required to perform these steps locally. |
+| [GitBook agent](https://gitbook.com/docs/gitbook-agent) and [Git Sync](https://gitbook.com/docs/getting-started/git-sync) | Offer agent editing and repository-synchronized documentation workflows. | Keep reviewable docs-as-code changes in the existing repository; preserve the current site stack. |
+| [GitLab documentation workflow](https://docs.gitlab.com/development/documentation/workflow/) | Couples docs to feature changes and expects technical and writing review, including for AI-assisted content. | Run source and editorial review as distinct checks. Do not transplant another organization's approval policy. |
+
+The common useful pattern is constrained drafting with repository context and explicit verification. Large prompts, fluent language, and a passing site build do not establish SDK correctness. The [study of 1,997 agent/human documentation PRs](https://arxiv.org/abs/2601.20171), submitted January 2026, reports limited human follow-up on agent edits in its sampled repositories. That is evidence about review activity in the sample, not a measurement of Oliphaunt's quality or proof that agent edits are wrong. It reinforces our decision to retain independent, deterministic checks.
+
+## How polyglot SDK docs arrange the learning path
+
+| Inspected source | Pattern worth using |
+| --- | --- |
+| [DuckDB client overview](https://duckdb.org/docs/stable/clients/overview) | Start with language/client choice and distinguish support levels while sharing database concepts. |
+| [Turso SDK introduction](https://docs.turso.tech/sdk/introduction) | Choose a package by language and use case; runtime choice matters as much as language. |
+| [Supabase JavaScript installation](https://supabase.com/docs/reference/javascript/installing) and [reference introduction](https://supabase.com/docs/reference/javascript/introduction) | Provide installation commands and concrete examples; organize lookup material around API operations. |
+| [Diátaxis introduction](https://diataxis.fr/start-here/) | Separate first learning, task instructions, technical lookup, and conceptual understanding. Apply the distinction without forcing four duplicate sections into every page. |
+| [shadcn/ui tabs](https://ui.shadcn.com/docs/components/radix/tabs) | Use an accessible primitive for interchangeable choices; retain predictable focus and keyboard behavior. |
+| [Fumadocs UI](https://www.fumadocs.dev/docs/ui) | Reuse the documentation framework's navigation, code blocks, search, and content components. |
+
+For Oliphaunt, this becomes: product and SDK choice → SDK installation and first query → common application tasks → deeper concepts and API lookup. Native and WASIX variants need explicit runtime labels. Quickstarts need full examples; conceptual pages need only examples that explain the concept. One shared concept page is preferable to eight repeated introductions.
+
+## AI authoring versus documentation for AI consumers
+
+These are different deliverables. The local skill teaches an agent how to change this repository. Public Markdown exports and search help an agent consume the product documentation. [Mintlify's skill.md documentation](https://www.mintlify.com/docs/ai/skillmd) describes a product-facing skill alongside its documentation index; that does not make a public authoring checklist necessary. Keep Oliphaunt's existing Markdown exports accurate and navigable, and keep maintainer authoring instructions local.
+
+## Decisions for this rewrite
+
+- Use one repository-local skill with two references, not copied external skill bundles or new paid services.
+- Audit every public page and all generated routes. Keep the audit and this research out of the public docs.
+- Replace duplicated landing summaries and hidden API links with a clear SDK quickstart, task guide, and visible API reference.
+- Generate version/catalog facts from existing authoritative metadata; verify published package claims separately.
+- Preserve important runtime and data-safety differences. Remove build-pipeline narration from developer pages.
+- Use real code examples and honest verification levels. Preserve meaningful checks while removing assertions tied only to the old wording or layout.
+- Reuse Fumadocs and its Radix-based components; review desktop/mobile screenshots and keyboard behavior after implementation.
+
+## Rebase review — 2026-09-29
+
+Revisited the requested examples against their current public docs:
+
+- [Turso TypeScript quickstart](https://docs.turso.tech/sdk/ts/quickstart): installation, connection, and a working SQL example precede optional synchronization. Adaptation: start with one complete query, then persistence and application recipes.
+- [PGlite getting started](https://pglite.dev/docs/): host-specific setup stays next to code; filesystems, workers, tools, and upgrade guidance have separate destinations. Adaptation: keep browser headers and mobile seeds mandatory in quickstarts, and put placement choices in guides.
+- [Supabase React quickstart](https://supabase.com/docs/guides/getting-started/quickstarts/reactjs): follows a framework-specific path from setup to a rendered application. Adaptation: say where code runs and link the next application task rather than explaining SDK implementation layers.
+- [Motion React docs](https://motion.dev/docs/react): short installation and import path, examples, then individual feature guides. Adaptation: compact introductions, task headings, and visible API navigation without decorative diagrams.
+
+These are structural observations, not borrowed prose or claims that Oliphaunt supports their features. The installed `better-writing` skill governs the edit. Current source APIs and centralized checkout versions stay paired; completed publication is recorded separately.
diff --git a/.codex/skills/write-oliphaunt-docs/references/source-map.md b/.codex/skills/write-oliphaunt-docs/references/source-map.md
new file mode 100644
index 000000000..9cd27698f
--- /dev/null
+++ b/.codex/skills/write-oliphaunt-docs/references/source-map.md
@@ -0,0 +1,62 @@
+# Oliphaunt documentation sources
+
+Paths are relative to the repository root. Recheck them when the code moves.
+
+## Content and generation
+
+| Source | Use |
+| --- | --- |
+| `src/docs/content/` | Authored public pages; read every file in scope |
+| `src/docs/docs-manifest.toml` | Route ownership, section order, sidebar entries, required SDK pages |
+| `src/docs/tools/generate-content.mts` | Copies/normalizes MDX; generates extension catalog, version matrix, navigation, and version snapshot |
+| `src/docs/src/lib/source.ts`, `src/docs/src/app/llms*` | Markdown text and exports from the same generated pages as the site |
+| `tools/policy/sdk-manifest.toml` | SDK package identity, snippet ownership, supported documentation surfaces |
+| `.release-please-manifest.json`, SDK `release.toml` files | Repository versions and publication identities; verify publication separately |
+| `src/docs/src/components/mdx.tsx`, `src/docs/src/app/global.css` | Available content components and site styling |
+| `src/docs/tools/check-docs-snippets.mts` | Strict source type-checks for complete TypeScript quickstarts; does not execute the database |
+| `src/docs/README.md` | Version tokens, build snapshots, generated platform data, authoring commands |
+| `src/docs/source.config.ts` | Fumadocs source and search processing |
+| `src/docs/maintainers/`, other `docs/` records | Authoring/engineering evidence, not public integration instructions |
+
+`target/docs/` is generated. Fix its source instead of editing output. Before removing a page or component, search content, navigation, Markdown exports, tests, and callers.
+
+## SDK contracts
+
+| SDK | First sources to inspect |
+| --- | --- |
+| Rust | `src/native/sdks/rust/src/lib.rs`, `builder.rs`, `database.rs`, `session.rs`, `storage.rs`, `server.rs`, `error.rs`; `tests/public_api.rs`, `tests/native_smoke.rs`; `Cargo.toml` |
+| TypeScript | `src/native/sdks/ts/src/index.ts`, `types.ts`, `client.ts`; `package.json`, `README.md`, tests and package export map |
+| Swift | `src/native/sdks/swift/Sources/Oliphaunt/`, `Package.swift`, `README.md`; released package-generation code for binary products |
+| Kotlin | `src/native/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroid.kt`; `src/commonMain/kotlin/`; `README.md` and Gradle plugin sources |
+| React Native | `src/native/sdks/react-native/src/index.ts`, `client.ts`; shared JS types, Expo plugin, `README.md` and native integration tests |
+| WASIX TypeScript | `src/wasix/sdks/ts/src/index.ts`, `types.ts`, `client.ts`, storage adapters, worker/server entry points; `tools-package/src/index.ts`; package export map |
+| WASIX Rust | `src/wasix/sdks/rust/src/lib.rs`, `src/oliphaunt/`, `Cargo.toml`; integration tests and examples |
+| C ABI | `src/native/runtime/include/oliphaunt.h`; implementation, ABI tests, and managed-root setup |
+
+Follow types into implementations for error recovery, transaction ownership, persistence, cancellation, restore compatibility, and shutdown. Read platform packaging code before claiming that an install command includes all required runtime assets.
+
+## Regression examples for this skill
+
+These were concrete accuracy problems found during the September 2026 rewrite. Verify the implementation again before using them as current facts.
+
+- Native direct mode stays bound to one root/configuration for the process lifetime. Closing does not permit opening restored data at another root; use broker mode on desktop or mobile broker setup; direct mobile restores use a subsequent process launch.
+- A fresh registry install can fail even when the checkout example compiles. Verify resource discovery, Cargo macro expansion in a consumer crate, and preservation of empty cluster-seed directories. Test packages before stating that runtime setup is automatic.
+- Kotlin `DatabaseStorage.Directory` receives `java.io.File`; mechanically reusing a JavaScript path string breaks the quickstart.
+- A PostgreSQL connection URL does not own the Rust server. A Tauri example must retain the server handle as long as its pool needs it.
+- Native and WASIX SDKs differ in defaults, storage adapters, concurrency, cancellation, and optional tools. A method present in one binding is not evidence for another.
+- A Swift source checkout and the generated release package can expose different packaging details. Match installation instructions to the consumer artifact.
+- Snippet comments in MDX identify ownership; they do not themselves execute or compare code. Report the actual validation level.
+
+## Commands
+
+Use the repository's required shell wrapper (`rtk`) where configured.
+
+```sh
+rtk proxy bun run --cwd src/docs check
+rtk proxy bun run --cwd src/docs build
+rtk proxy bun run --cwd src/docs smoke
+```
+
+Read `src/docs/package.json` and its task scripts before choosing a narrower command. Check `qualify-oliphaunt-change` when SDK code or release products also change. Do not run publication or native release qualification merely for a prose edit.
+
+For browser review, use the existing docs dev command and a free localhost port. Capture screenshots outside published content; keep review artifacts and per-file findings in the maintainer audit. Do not check in generated site output.
diff --git a/README.md b/README.md
index 901628fbc..b98ef8dfe 100644
--- a/README.md
+++ b/README.md
@@ -1,146 +1,44 @@
-
+
-
- Native-first embedded PostgreSQL 18 for desktop, mobile, and WASIX applications. Same engine, new name: pglite‑oxide is now Oliphaunt.
-
-
-
-
-
-
-Oliphaunt is a family of peer SDKs and runtime products over the same embedded
-PostgreSQL model. Applications own their database roots, choose an honest
-runtime mode for their platform, and package only the exact PostgreSQL
-extensions they select.
-
-## Product model
-
-Oliphaunt is a multi-product monorepo, not one repository-wide version:
-
-- `liboliphaunt-native` owns the PostgreSQL 18 C ABI runtime and native target
- carriers.
-- `liboliphaunt-wasix` owns portable WASIX runtime assets and host AOT
- carriers.
-- `liboliphaunt-wasix-postmaster` owns the concurrent Linux x64 GNU and macOS arm64 WASIX
- postmaster carrier with isolated PostgreSQL backends.
-- Native and WASIX own independent versions. A change to one does not select
- the other unless a declared directed compatibility dependency requires it.
-- Rust, Swift, Kotlin/Android, React Native, TypeScript, Rust WASIX, and WASIX
- TypeScript are separately versioned SDK products.
-- Broker and Node-direct helpers are separately versioned runtime products.
-- Every SQL extension in the catalog remains exactly selectable. PostgreSQL 18
- contrib members share one logical artifact bundle whose native and WASIX
- carriers belong to their respective runtime releases; each external extension
- is a separately tagged, independently versioned product.
-
-A product owns its SemVer, changelog, source identity, product tag, and GitHub
-release. Platform packages, ABI payloads, and size-split crates are carriers of
-that product; they use the product version and are not extra products.
-
-## First-release target envelope
+# PostgreSQL inside your application
-The release target manifests currently declare:
+Oliphaunt embeds PostgreSQL 18 in desktop, mobile, and browser applications. Use PostgreSQL SQL, types, transactions, and extensions through an SDK for your language, without setting up a separate database service.
-| Surface | Declared release targets |
-| ---------------- | -------------------------------------------------------------------------------------------------------------------------- |
-| Desktop native | Linux x64 GNU, Linux arm64 GNU, macOS arm64, Windows x64 MSVC |
-| Android | `arm64-v8a`, `x86_64` |
-| Apple | iOS XCFramework carrier plus the declared macOS arm64 runtime carrier, delivered through SwiftPM and GitHub release assets |
-| WASIX | portable runtime plus AOT carriers for Linux x64/arm64 GNU, macOS arm64, and Windows x64 MSVC |
-| WASIX postmaster | sealed concurrent runtime carriers for Linux x64 GNU and macOS arm64 |
+## Get started
-The first release intentionally does **not** claim macOS x64, Windows ARM64,
-Linux musl, Android 32-bit, or undeclared Apple architectures. A compiler,
-language, or runtime working on a broader platform is not a support promise;
-the explicit target manifest, publication catalog, and frozen release lock are
-the boundary.
+Choose the SDK for your application. Each quickstart covers installation, a complete query, and persistent storage.
-Exact-extension support is target-specific too. An extension is publishable
-for a target only when its own target manifest and evidence declare that row.
-The public [release reference](src/docs/content/reference/releases.mdx)
-publishes the enforced OS/API/ABI floors and distinguishes built package
-coverage from installed-app execution evidence, including the Android arm64
-and physical-iOS boundaries.
+| Application | SDK | Package |
+| --- | --- | --- |
+| Rust and Tauri | [Rust](https://oliphaunt.dev/docs/sdk/rust) | `oliphaunt` |
+| Node.js, Bun, Deno, Electron | [TypeScript](https://oliphaunt.dev/docs/sdk/typescript) | `@oliphaunt/ts` |
+| iOS and macOS | [Swift](https://oliphaunt.dev/docs/sdk/swift) | `Oliphaunt` |
+| Android | [Kotlin](https://oliphaunt.dev/docs/sdk/kotlin) | `dev.oliphaunt:oliphaunt-android` |
+| React Native and Expo native builds | [React Native](https://oliphaunt.dev/docs/sdk/react-native) | `@oliphaunt/react-native` |
+| Browsers and JavaScript runtimes using WebAssembly | [WASIX TypeScript](https://oliphaunt.dev/docs/sdk/wasix-typescript) | `@oliphaunt/wasix-ts` |
+| Rust using WebAssembly | [WASIX Rust](https://oliphaunt.dev/docs/sdk/wasix-rust) | `oliphaunt-wasix` |
+| C, C++, and language bindings | [C ABI](https://oliphaunt.dev/docs/sdk/c-abi) | `liboliphaunt` |
-## SDK entry points
+## How it works
-The declared public entry points are:
+An embedded handle owns one PostgreSQL session. Bind parameters, query rows, and use callback transactions through the SDK. Choose persistent storage to keep data between application runs.
-| App surface | Package entry point | Distribution boundary |
-| -------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------ |
-| Rust/Tauri desktop | `oliphaunt` | Cargo and target-specific native artifact crates |
-| Rust WASIX | `oliphaunt-wasix` | Cargo portable/AOT artifact crates |
-| WASIX postmaster server | `oliphaunt-wasix-postmaster` release launcher | GitHub `linux-x64-gnu` or `macos-arm64` sealed carrier archive |
-| Swift | `Oliphaunt` | SwiftPM source tag and checksum-pinned release assets |
-| Android | `dev.oliphaunt:oliphaunt-android` and `dev.oliphaunt.android` | Maven Central AAR, Gradle plugin/marker, and declared ABI carriers |
-| React Native | `@oliphaunt/react-native` | npm package delegating runtime work to Swift and Kotlin |
-| Node.js, Bun, and Deno | `@oliphaunt/ts` | npm |
-| Browser, Node.js, Bun, and Deno WASIX | `@oliphaunt/wasix-ts` | npm |
-| Native bindings | `liboliphaunt` C ABI | declared native runtime carriers |
+Native Rust and desktop TypeScript also offer a broker process and a local PostgreSQL server. Server mode supports standard drivers, ORMs, and independent client sessions. Browser applications use the WASIX TypeScript Worker integration.
-Kotlin common sources are compiled and tested on the JVM as development
-evidence, but only the Android facade is supported and published. The first Swift release starts at
-`0.6.0` because legacy unscoped SwiftPM tags already occupy `0.1.0` through
-`0.5.1`; other new products start at `0.1.0`.
+Select extensions before opening a database, then enable them with SQL such as `CREATE EXTENSION vector`. Package only the native resources your application needs. Runtime and extension versions have their own compatibility requirements.
-## Exact extensions
-
-Extension selection uses exact PostgreSQL SQL names. There are no selection
-packs, aliases, or implicit groups; the contrib distribution bundle is only a
-carrier envelope. Selecting `earthdistance` may include its declared `cube`
-dependency; selecting `vector` does not pull unrelated extensions into the
-application.
-
-The logical `oliphaunt-extension-contrib-pg18` bundle has no independent
-version or release. Its native carriers follow `liboliphaunt-native`; its WASIX
-carriers follow `liboliphaunt-wasix`. Each carrier contains an exact,
-checksummed member inventory, but consumers stage only requested SQL members.
-External extension products own independent packaging SemVer. Their immutable
-upstream version/commit and compatible Oliphaunt runtime versions are recorded
-separately, so consumers must not infer compatibility from matching version
-numbers.
-
-## Development
-
-Install the pinned toolchain once, then use Moon as the repository task
-surface:
-
-```sh
-proto upgrade 0.61.3
-proto install
-tools/dev/bootstrap-tools.sh
-moon query tasks --project oliphaunt-rust
-moon run oliphaunt-rust:build oliphaunt-rust:test oliphaunt-rust:package
-```
-
-Choose the project you are changing; its tasks own the required checks and
-build tools. For workflow checks alone, `tools/dev/bootstrap-tools.sh --workflows`
-installs Actionlint and Zizmor. The default also installs Prek and cargo-nextest.
-
-For a product metadata change, also run the metadata gate:
-
-```sh
-moon run release-tools:metadata
-```
-
-Use `release-tools:test` or `ci-workflows:check` when its
-corresponding machinery changes. Reserve `release-tools:check` for an exact
-release candidate.
+## Documentation
-The protected GitHub `Release` workflow owns candidate dry-runs and all public
-mutation. Local development commands do not publish packages, create tags, or
-promote releases.
+- [Get started](https://oliphaunt.dev/docs/start)
+- [Runtime and platform support](https://oliphaunt.dev/docs/reference/capabilities)
+- [Extensions](https://oliphaunt.dev/docs/reference/extensions)
+- [Moving from SQLite](https://oliphaunt.dev/docs/learn/sqlite-upgrade)
+- [Releases and upgrades](https://oliphaunt.dev/docs/reference/releases)
-## Documentation
+## Contributing
-- [Public SDK documentation](src/docs/content/sdk/index.mdx)
-- [Runtime support](src/docs/content/reference/capabilities.mdx)
-- [Exact extension model](src/docs/content/reference/extensions.mdx)
-- [Source architecture](src/docs/architecture/final-product-source-architecture.md)
-- [Maintainer documentation index](src/docs/maintainers/README.md)
-- [Release process](src/docs/maintainers/release.md)
-- [Contributing](CONTRIBUTING.md)
+See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and the [maintainer index](src/docs/maintainers/README.md) for architecture, testing, and release procedures.
-Oliphaunt is licensed under the terms recorded in [LICENSE](LICENSE).
+Oliphaunt is licensed under [MIT](LICENSE).
diff --git a/bun.lock b/bun.lock
index 08df9a29f..843779cee 100644
--- a/bun.lock
+++ b/bun.lock
@@ -29,7 +29,6 @@
"fumadocs-mdx": "15.0.10",
"fumadocs-ui": "16.9.3",
"lucide-react": "^1.17.0",
- "motion": "13.1.0",
"next": "16.2.7",
"react": "19.2.7",
"react-dom": "19.2.7",
@@ -168,7 +167,7 @@
"name": "@oliphaunt/react-native",
"version": "0.3.0",
"dependencies": {
- "@oliphaunt/ts-query": "0.1.0",
+ "@oliphaunt/ts-query": "0.1.1",
},
"devDependencies": {
"@react-native/codegen": "^0.85.3",
@@ -192,7 +191,7 @@
"name": "@oliphaunt/ts",
"version": "0.3.0",
"dependencies": {
- "@oliphaunt/ts-query": "0.1.0",
+ "@oliphaunt/ts-query": "0.1.1",
},
"devDependencies": {
"@types/bun": "catalog:",
@@ -290,7 +289,7 @@
"name": "@oliphaunt/wasix-ts",
"version": "0.2.0",
"dependencies": {
- "@oliphaunt/ts-query": "0.1.0",
+ "@oliphaunt/ts-query": "0.1.1",
"fzstd": "0.1.1",
},
"devDependencies": {
@@ -1732,7 +1731,7 @@
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
- "framer-motion": ["framer-motion@13.1.0", "", { "dependencies": { "motion-dom": "13.0.0", "motion-utils": "13.0.0", "tslib": "2.8.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-QSZrF0Id3QGuHJ+OL+9PSY9pk86C8ERFalwAGSchzTm65+ZoGH/RM26lmEARLljcHj2lqhv0jZOOks+EI3COOw=="],
+ "framer-motion": ["framer-motion@12.40.0", "", { "dependencies": { "motion-dom": "12.40.0", "motion-utils": "12.39.0", "tslib": "2.8.1" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg=="],
"fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="],
@@ -2260,11 +2259,11 @@
"modify-values": ["modify-values@1.0.1", "", {}, "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw=="],
- "motion": ["motion@13.1.0", "", { "dependencies": { "framer-motion": "13.1.0", "tslib": "2.8.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-qtvscq59uCPdWnNW4SdSkrxR+BS/QYsa923bx7ocA+4p+ZGNbbVQwkSnG4aukB81QWjtl3AxX36plxNyZLmHCA=="],
+ "motion": ["motion@12.40.0", "", { "dependencies": { "framer-motion": "12.40.0", "tslib": "2.8.1" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA=="],
- "motion-dom": ["motion-dom@13.0.0", "", { "dependencies": { "motion-utils": "13.0.0" } }, "sha512-Xk+SJas70uMAUIApg+m3lZDShxI3LBFHq7mFGbBKoRXc2PVPDyAKmzN64Bbzt4CZdP/CItTiJxWtn4TA0v53Ng=="],
+ "motion-dom": ["motion-dom@12.40.0", "", { "dependencies": { "motion-utils": "12.39.0" } }, "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg=="],
- "motion-utils": ["motion-utils@13.0.0", "", {}, "sha512-7DnN7TmbLcYXcG4RVadXIihWlyuM9afoUww8Y5Agg431kGKiuL2/OMyP4mJ5wLz+pvN3t5ySClLOaVXJ+wekRQ=="],
+ "motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
@@ -3114,8 +3113,6 @@
"foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
- "fumadocs-ui/motion": ["motion@12.40.0", "", { "dependencies": { "framer-motion": "12.40.0", "tslib": "2.8.1" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA=="],
-
"glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
"handlebars/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
@@ -3310,8 +3307,6 @@
"finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
- "fumadocs-ui/motion/framer-motion": ["framer-motion@12.40.0", "", { "dependencies": { "motion-dom": "12.40.0", "motion-utils": "12.39.0", "tslib": "2.8.1" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg=="],
-
"glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="],
"jest-util/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
@@ -3388,10 +3383,6 @@
"@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
- "fumadocs-ui/motion/framer-motion/motion-dom": ["motion-dom@12.40.0", "", { "dependencies": { "motion-utils": "12.39.0" } }, "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg=="],
-
- "fumadocs-ui/motion/framer-motion/motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="],
-
"glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"log-symbols/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
diff --git a/src/docs/DESIGN_GROUNDING.md b/src/docs/DESIGN_GROUNDING.md
index 2f3864f57..32045ed3b 100644
--- a/src/docs/DESIGN_GROUNDING.md
+++ b/src/docs/DESIGN_GROUNDING.md
@@ -1,108 +1,35 @@
-# Oliphaunt Docs Design Grounding
+# Documentation design
-This file keeps the docs-site work scoped to the visual and UX foundation for
-`docs`.
+The reading task comes first: choose a runtime, install a package, run a query, and find the next integration detail. The visual design should make those steps easy to scan.
-## Goal
+## Structure
-Build a striking, mobile-first docs foundation for Oliphaunt. The site should
-feel like a polished product surface for a polyglot embedded PostgreSQL library:
-SDK packages, runtime modes, tooling, maintainer paths, and equivalent examples
-across languages.
+- One documentation shell at the homepage and every docs route.
+- A shallow sidebar: Get started, SDKs, Guides, Reference. Expand the active SDK and expose its guide and API reference.
+- SDK rows where the reader chooses a language/runtime. Use prose, lists, and tables within documentation.
+- Compact page titles, readable code, a restrained line length, and a local table of contents.
+- Shared concepts live in shared guides. Put platform exceptions next to the relevant command.
-Documentation completeness is secondary. Presentation, wayfinding, interaction,
-light/dark quality, and reusable docs affordances are the work.
+## Components and style
-The active quality bar is Motion-level craft across the whole docs app, not just
-the first viewport. Every pass should re-check Motion, inspect rendered
-Oliphaunt pages, remove redundant or over-boxed UI, and keep code-looking text
-semantic: inline code for identifiers, real code blocks for commands/examples.
+Reuse Fumadocs navigation, search, code copying, cards, callouts, steps, and Radix tabs. These provide the same accessible primitive approach used by shadcn/ui. Do not add a second component framework for equivalent controls.
-## Motion Docs Takeaways
+Use the available better-interface skills for layout, writing, typography, color, accessibility, and UI review. The visual references are [f0rr0.dev](https://f0rr0.dev), [GPU Postal](https://gpu-postal.f0rr0.dev), and [mealprep.party](https://mealprep.party). Their live pages and repository styles informed the near-black surfaces, quiet gray dividers, compact regular-weight headings, and limited illustration.
-Observed from `https://motion.dev/docs`, `/docs/react`, and deeper docs pages:
+Use DM Sans for reading and section headings, Instrument Serif only for page titles, and Geist Mono for code and utility labels. The type roles are 40px page titles, 18px section titles, 16px prose, 14px supporting text, 13px code, and 12px utility labels. Favor regular and medium weights; the compact wordmark uses 18px semibold.
-- Oversized, confident page titles with tight copy and generous vertical rhythm.
-- Small monospace section labels, breadcrumbs, and version-like pills create a
- product/manual feel.
-- The best visual texture is functional: line grids, diagonal hatching, compact
- charts, code, and live-demo surfaces.
-- Cards are crisp and low-radius, often row-based rather than decorative.
-- Motion's docs home uses a dark product/manual surface, a compact technical
- chart, a small set of primary route cards, and row-based secondary links; it
- does not repeat full tutorial content on the landing page.
-- Mobile strips the experience down to strong title, intro, actions, and content;
- side navigation should not dominate the first screen.
-- Animations should be restrained: subtle entrances, hover shifts, focus states,
- and ambient technical motion that respects reduced-motion.
-- Code examples need to feel central and copyable, with clear language switching
- for the same app flow.
-- Docs pages rely mostly on prose, rows, dividers, tables, and occasional code;
- custom panels should be rare and earn their space.
+Use a centered 1248px layout: 256px navigation, 768px article, and 224px table of contents when all columns fit. Article gutters are 32px on desktop and 16px on narrow screens. Align breadcrumbs, headings, prose, code blocks, and SDK names to the same leading edge. Align page-title tops even when artwork is present.
-## Oliphaunt Foundation Principles
+Body text and SDK labels follow a 24px line rhythm. Use 16px paragraph spacing, 32px between the page header and body, and 48px before new sections. SDK rows are at least 80px, including their divider; wrapped descriptions add whole text lines. The SDK grid becomes two columns only when its own available width accommodates two 288px columns and a 32px gap. Avoid separate decorative icon columns that interrupt the text alignment.
-- Keep the first screen product-like: Oliphaunt, embedded PostgreSQL, SDKs,
- runtime modes, and a visible code/system artifact.
-- Use a balanced palette: ink/ivory neutrals with green as primary, amber/cyan
- accents for state and language surfaces. Avoid a one-note green or slate UI.
-- Keep page sections unframed; cards are only for repeated items and tools.
-- Use 8px or smaller radii unless Fumadocs requires otherwise.
-- Prefer icons for recognisable tools/actions, with text for clear commands.
-- Make polyglot examples a first-class pattern, not an afterthought.
-- Maintain light and dark mode parity.
-- Preserve generated-content boundaries: edit presentation components, app
- routes, theme CSS, and docs-app metadata; avoid changing generated targets.
-- Prefer divider-based row lists over nested cards when the user is choosing
- among pages, SDKs, modes, or reference lookups.
+Default to dark, while retaining the reader's light-theme choice. Use neutral semantic Tailwind tokens for surfaces, text, focus, and active navigation; keep syntax highlighting useful. The identity is an open, solid O with a curved terminal, paired with a lowercase wordmark. Reuse its geometry in navigation, the favicon, and social previews.
-## Review Protocol
+Use the monochrome elephant engraving on the start page as editorial artwork. Keep its original aspect ratio and transparency, top-align it with the title, and hide it on narrow screens so SDK selection stays near the top. Avoid cartoon mascots, extra illustration panels, animation, and canvas code. The saved asset and generation prompt are recorded in the [audit](maintainers/docs-rebase-audit.md#identity-and-spacing-refinement--2026-09-29).
-- Revisit the docs app on mobile and desktop after substantial layout edits.
-- Run `bun run --cwd docs check` before handing off docs changes.
-- Use `bun run --cwd docs build` when changes touch route composition,
- metadata, generated content, or Next.js boundaries.
+Keep interactions quiet and functional. Respect reduced motion. Maintain contrast in both themes and visible keyboard focus. Provide a first-tab skip link and a main landmark. Long code and tables scroll within their containers; the page must fit a 320px viewport.
-## Implementation Checklist
+## Visual review
-- [x] Scope remains inside `docs`.
-- [ ] Landing page and every docs route reach Motion-level cleanliness on mobile
- and desktop.
-- [x] Light and dark mode both have intentional contrast and texture.
-- [ ] Navigation and doc reading surfaces feel compact, clean, and polished on
- every route.
-- [x] Polyglot code examples show the same flow across languages.
-- [ ] Reusable MDX components share a restrained row/table/prose visual language.
-- [x] Browser screenshots reviewed full-page on mobile and desktop after each
- major slice.
-- [x] Motion reference pages reviewed during each active implementation turn.
-- [x] `bun run --cwd docs check` or best available equivalent is
- run before final handoff.
+Inspect the actual production export at desktop and mobile widths, in light and dark modes. Include the start page, a quickstart, an API reference, and long reference tables. Exercise mobile navigation, search, tabs by keyboard, code copying, and Markdown exports.
-## Current Slice Notes
-
-- Landing was reduced to hero, SDK choices, and reference paths; standalone
- landing code comparisons and repeated runtime/src/docs/CTA sections were removed.
-- `/docs/start` was reduced to quickstart, first-query comparison, and next
- steps; redundant outcome and verify panels were removed.
-- `/docs/learn` was converted from card-heavy maps/tabs to divider rows and
- prose bullets.
-- `/docs/sdk` moved from card-heavy SDK chooser and runtime matrix to divider
- rows. Focused audit improved `borderedPanels` from 35 to 13 and code blocks
- from 7 to 0 on the SDK index.
-- Reference lookup/capability/extension/performance/release components moved
- from boxed grids to divider rows. The audit metric now separates icon tiles
- from real bordered panels.
-- This pass refreshed Motion `/docs`, `/docs/react`, `/docs/react-animation`,
- `/docs/react-transitions`, and `/docs/react-layout-animations` screenshots.
-- Home now uses a dark Motion-like technical hero, a visible mobile product map,
- and SDK rows instead of seven uneven SDK cards.
-- `/docs/start` now uses unboxed quickstart rows, flatter code blocks, and
- row-based next steps. Focused audit improved `borderedPanels` from 8 to 2 on
- desktop and mobile with no horizontal overflow.
-- Install prose no longer renders as terminal code in shared SDK summary
- components; real install commands remain code blocks.
-- Next likely targets from full audit: React Native/native runtime panels,
- embedded/mobile/SQLite/Tauri/WASM `gap-px bg-fd-border` grids, SDK index
- content duplication, API reference identifier semantics, and tabbed polyglot
- code affordances.
+Keep screenshots and measurements in review artifacts. Use the [audit](maintainers/docs-rebase-audit.md) for results and limitations; do not turn public pages into implementation progress logs.
diff --git a/src/docs/README.md b/src/docs/README.md
index f404a5fc9..60da889a0 100644
--- a/src/docs/README.md
+++ b/src/docs/README.md
@@ -7,17 +7,25 @@ Authored SDK API maps remain ordinary guides.
From this directory after installing the root Bun workspace:
- `bun run dev`: prepare content and start Next.js.
-- `bun run check`: check internal links and TypeScript.
+- `bun run check`: check internal links, site TypeScript, and TypeScript quickstart snippets.
- `bun run test`: exercise published-release selection and refresh-request handling.
-- `bun run build`: resolve fresh completed releases and export the site.
+- `bun run build`: resolve versions, type-check TypeScript quickstarts, and export the site.
- `bun run smoke`: check exported routes and text endpoints.
-Published versions come from GitHub's completed, non-prerelease product releases,
-never the Release Please candidate manifest. Unreleased resource and package
-separation examples carry an explicit development label; remove that label only
-after the corresponding products are publicly available. Kotlin's plugin and library use
-the same product version. SDK packages own their compatible runtime dependencies;
-guides do not independently select a newer runtime.
+## Versions and example accuracy
+
+These guides target the current checkout, per the documentation rewrite's scope.
+`{{release:product-id}}` resolves the owning path in `release-please-config.json`
+to `.release-please-manifest.json`. Updating a product version therefore updates
+all its public install examples without editing individual pages. Generated
+`docs-version.json` records the resolved map and source revision; set
+`OLIPHAUNT_DOCS_GIT_SHA` for a local archived build (Vercel uses its commit SHA).
+Keep this record with an archived static export. No historical picker is hosted.
+
+The version table separately lists completed stable GitHub releases. Never label
+current-checkout examples with an older published version. A source build does
+not prove registry availability; release qualification verifies the documented
+package set before publication. SDK dependencies select compatible runtimes.
Each preparation resolves GitHub metadata anew and fails on network errors.
For an explicit offline build set `OLIPHAUNT_DOCS_RELEASES_FILE` to a previously
@@ -65,5 +73,18 @@ External prerequisites still required:
the hook's job ID. Vercel's Git integration owns guide deployment status;
verify its production promotion and ordering in the project dashboard.
-Task 23a remains partial until those prerequisites and deployment verification
-are complete. See [Vercel's deploy-hook contract](https://vercel.com/docs/deploy-hooks).
+Verify those prerequisites before relying on automatic release refresh. See [Vercel's deploy-hook contract](https://vercel.com/docs/deploy-hooks).
+
+## Authoring and review
+
+Use [write-oliphaunt-docs](../../.codex/skills/write-oliphaunt-docs/SKILL.md) and
+`better-writing`. The public path is SDK choice → installation → first query →
+persistence → application recipes → API lookup. Keep maintainer procedures and
+validation limitations under `maintainers/`. Review every edited example against
+its own SDK, including defaults, extension descriptors, resource prerequisites,
+and restore destinations.
+
+The sidebar follows `docs-manifest.toml`. The platform table is generated from
+release compatibility policy, and the extension catalog from generated extension
+metadata. Next/Fumadocs exports Markdown and search from the same pages as HTML;
+do not overwrite those text exports with a second static generator.
diff --git a/src/docs/content/learn/embedded-postgres.mdx b/src/docs/content/learn/embedded-postgres.mdx
index f38fd65d7..1ed6b5378 100644
--- a/src/docs/content/learn/embedded-postgres.mdx
+++ b/src/docs/content/learn/embedded-postgres.mdx
@@ -1,79 +1,44 @@
---
-sidebar_position: 1
title: Embedded PostgreSQL
-description: Learn how PostgreSQL storage, WAL, lifecycle, extensions, backup, and restore fit inside an app.
+description: Understand database lifetime, persistence, and backup in an embedded PostgreSQL app.
---
-# Embedded PostgreSQL
+Oliphaunt runs PostgreSQL inside your application or a local process it owns. Your app chooses when the database opens, where its data lives, and when it closes. PostgreSQL supplies SQL execution, transactions, indexes, and recovery.
-Oliphaunt embeds PostgreSQL behind SDK-native APIs while keeping PostgreSQL's
-storage, WAL, SQL, protocol, and extension model recognizable. The SDK boundary
-owns lifecycle, packaged runtime assets, exact extension selection, and app-safe
-defaults.
+## Choose the data lifetime
-
+| Storage | Use it for | What happens after close |
+| --- | --- | --- |
+| Native default: temporary directory | Tests, previews, disposable work | Disposable; do not rely on it surviving the process |
+| WASIX default: memory filesystem | Tests and disposable browser or host sessions | The data is discarded |
+| Persistent directory or browser provider | Application data | Reopen the same storage to use the data again |
-The product line has distinct native and WASIX hosts.
+Choose persistent storage explicitly before saving user data. Native mobile apps normally use an app-private directory. WASIX browser apps choose IndexedDB or OPFS; desktop WASIX apps can use a directory.
-| Product | Use it for |
-| --- | --- |
-| Native `liboliphaunt` SDKs | Rust, Swift, Kotlin, React Native, TypeScript, and C ABI consumers |
-| Rust WASIX `oliphaunt-wasix` | Rust applications hosting the portable runtime |
-| WASIX TypeScript `@oliphaunt/wasix-ts` | Browser caller-realm root; native-host actor root, explicit `/direct`, or `/worker` on Node, Bun, Deno, and Electron; browsers may opt into IndexedDB or OPFS persistence and native hosts may opt into directory persistence |
+A native persistent database is a managed directory, not a single file. Let the SDK manage its contents. Do not delete database files or open the same root through another database instance.
-The products share storage, exact extension selection, structured errors, and
-lifecycle concepts. Backup/restore, server access, and persistence mechanisms
-remain product-specific and are recorded in the static runtime-support matrix.
+## One handle, one session
-## Database storage
+Embedded query handles use one PostgreSQL session. Async calls let the application stay responsive, but queries still execute in order on that session. A transaction holds the session until it commits or rolls back.
-A managed persistent root contains `.oliphaunt.json` and `pgdata`. PostgreSQL
-owns the data, WAL, catalog state for installed extensions, and recovery state
-inside `pgdata`. Binding-local locks or leases are host coordination state, not
-database contents. Native temporary storage is SDK-owned. WASIX uses a true
-memory filesystem by default and offers host-specific persistent storage
-explicitly.
+Use the transaction object supplied to a callback for every operation inside it. Calling the outer database handle from the callback can wait on the transaction that is already using the session.
-That storage model is deliberate: app developers get PostgreSQL's recovery and SQL
-behavior, while the SDK owns the app-facing safety rails around paths, locking,
-backup, restore, and selected runtime assets.
+For independent client sessions and a connection pool, use a [native server](/docs/learn/native-runtime#server). WASIX local endpoints accept one connected client at a time.
-## Lifecycle Contract
+## Store changes safely
-Every SDK exposes open, query, and close with ecosystem-native names. Other
-lifecycle phases are present only where the host supports them:
+PostgreSQL uses write-ahead logging, or WAL, to recover committed changes after an interruption. Native SDKs use PostgreSQL's files directly. Persistent WASIX providers also need to publish changes to their host storage; follow the SDK's persistence contract.
-| Phase | What the SDK owns |
-| --- | --- |
-| Open | Create or attach to storage, validate ownership, and materialize selected runtime resources |
-| Query | Route work through the selected engine and preserve mode-specific concurrency rules |
-| SQL maintenance | Applications may issue PostgreSQL `CHECKPOINT` through ordinary `execute`; WASIX TypeScript then publishes through its selected provider. There is no SDK checkpoint method |
-| Close | Reject new work, wait for active work, and detach cleanly from the selected runtime |
-| Backup/restore | Use each binding's physical data-movement API where exposed |
+Await operations and close the database explicitly. Mobile operating systems may terminate an app without calling shutdown code, so closing must not be your only persistence mechanism. Keep transactions short and treat an interrupted operation with an unknown result as uncertain; check application state before retrying it.
-Applications decide when platform lifecycle events require SQL maintenance,
-cancellation, or close. Desktop SDKs add broker and server modes where a helper
-process or local server is the better runtime shape.
+## Back up a database
-## Extension Selection
+Use the SDK's `backup` and `restore` APIs. A live directory copy can miss files or WAL needed for a consistent database. Restore into a new or empty destination, then open that destination with the required extensions available.
-Extensions are selected exactly before packaging or opening the database.
-Native SDKs use SQL-name selectors, Rust WASIX uses exact Cargo features and
-typed values, and WASIX TypeScript imports exact `-wasix` descriptors. App
-artifacts include only the selected carrier closure.
+Physical archives belong to their runtime family and require a compatible runtime version. Use a logical SQL dump when moving between native and WASIX runtimes. Backups contain database state; ship extension binaries and resources with the destination application separately.
-`CREATE EXTENSION` succeeds only when the selected runtime resources include
-that extension for the target platform. See the
-[extension reference](/docs/reference/extensions) for the distribution contract.
+## Use PostgreSQL features
-## What is different from SQLite?
+Parameters use PostgreSQL's `$1`, `$2` syntax. Types, casts, constraints, and query planning follow PostgreSQL behavior. [Extensions](/docs/reference/extensions) add features such as vector search; select and package an extension before enabling it with SQL.
-Oliphaunt stores live data as PostgreSQL storage with PostgreSQL recovery
-behavior. On native targets this is a directory rather than a single database
-file; WASIX hosts provide their own storage policy. That is a larger runtime model,
-but it enables PostgreSQL SQL, types, wire-protocol behavior, and extensions
-inside apps that need those features.
-
-Use SQLite when a small single-file database is the better product fit. Use
-Oliphaunt when PostgreSQL compatibility, extensions, or server-compatible
-workflows are worth the extra runtime footprint.
+Use the [SDK guides](/docs/sdk) for concrete storage, transaction, and backup examples.
diff --git a/src/docs/content/learn/index.mdx b/src/docs/content/learn/index.mdx
index 896f21419..6e8ff9b76 100644
--- a/src/docs/content/learn/index.mdx
+++ b/src/docs/content/learn/index.mdx
@@ -1,32 +1,14 @@
---
-title: Learn
-description: Understand Oliphaunt's runtime model before choosing production settings.
+title: Guides
+description: Understand storage, choose a runtime, and integrate Oliphaunt into your app.
---
-# Learn
+Use these guides after completing your [SDK quickstart](/docs/sdk). For code specific to your language, open the guide under that SDK.
-Use these pages after the first query works and you need to make production
-choices: where data lives, which runtime boundary fits, how mobile lifecycle
-behaves, and how to package the app without extra extension files.
-
-
-
-## Suggested Paths
-
-- **Mobile apps:** Read [Embedded PostgreSQL](/docs/learn/embedded-postgres),
- then [Mobile Stability](/docs/learn/mobile-stability). React Native developers
- then read the [React Native architecture page](/docs/sdk/react-native/architecture)
- before wiring app lifecycle policy or moving large protocol responses.
-- **Desktop apps:** Read [Native Runtime](/docs/learn/native-runtime) first.
- Tauri developers then read [Tauri Usage](/docs/learn/tauri) and keep database
- ownership in Rust state.
-- **SQLite migration:** Read [Moving From SQLite](/docs/learn/sqlite-upgrade),
- then use [Extensions](/docs/reference/extensions) and
- [Performance](/docs/reference/performance) while sizing the app artifact and
- benchmark plan.
-
-## What Learn Covers
-
-Learn pages explain product behavior in app terms. Use the SDK page when you
-need install steps and code. Use Reference when you need a matrix, catalog, or
-version lookup.
+
+
+
+
+
+
+
diff --git a/src/docs/content/learn/mobile-stability.mdx b/src/docs/content/learn/mobile-stability.mdx
index 91a04bfc1..54207f0fc 100644
--- a/src/docs/content/learn/mobile-stability.mdx
+++ b/src/docs/content/learn/mobile-stability.mdx
@@ -1,207 +1,109 @@
---
-title: Mobile Stability
-description: Understand native direct mode, relaunch, persistence, and crash consistency on iOS, Android, and React Native.
+title: Ship a mobile database
+description: Manage persistent storage, transactions, and application lifecycle on iOS and Android.
---
-# Mobile Stability
+Mobile apps need a database that survives normal process termination. Start with the [Swift](/docs/sdk/swift), [Kotlin](/docs/sdk/kotlin), or [React Native](/docs/sdk/react-native) quickstart, then apply these practices before shipping.
-Oliphaunt mobile SDKs default to native direct mode. The explicit broker mode
-places PostgreSQL in a platform-owned worker process while keeping the same
-query, transaction, cancellation, and backup APIs. Both modes serialize one
-physical PostgreSQL session.
+## Keep data in app-private storage
-
+Choose a stable application-data directory. Temporary storage is useful for tests but does not retain user data. On React Native, `applicationData` storage resolves a name through the platform SDK.
-## What developers can rely on
+Use the platform's file-protection and backup settings for your app's data. Do not move, rename, or copy a live PostgreSQL root. Export a database through the SDK backup API when a user needs to move it.
-- PostgreSQL storage and WAL provide crash recovery.
-- Reopening the same persistent storage after app relaunch recovers the
- database.
-- Concurrent app tasks share one serialized physical database session.
-- React Native delegates execution to Swift on Apple platforms and Kotlin on
- Android.
+## Own the database at application scope
-Direct mode shares the app process. It does not promise process isolation,
-independent PostgreSQL sessions, or multiple resident database instances.
+Open the database in an application service or state owner. Avoid opening a new database for each screen render or query. Share the handle through Swift concurrency, Kotlin coroutines, or the React Native client.
-## Close and reopen
+Direct mode binds the process to one root and configuration. Closing the database does not unload the backend. If you restore into a new root, switch to it on a subsequent application launch.
-In direct mode, `close()` logically detaches the SDK handle. The same database
-instance can reopen while the process remains resident; switching persistent
-roots requires a fresh process. Broker close retires its worker. A subsequent
-explicit open creates a fresh worker and can select another named database.
-
-Use an app-owned persistent storage location for user data. Temporary storage
-is appropriate for tests and short-lived work.
-
-## Background and foreground
-
-The SDK exposes normal database operations, not an app-background mode. The app
-decides whether a platform lifecycle event cancels bounded work or closes the
-database. Committed work relies on PostgreSQL WAL and crash recovery; routine
-app lifecycle handling does not require an SDK checkpoint method. A maintenance
-workflow that explicitly needs `CHECKPOINT` can issue that PostgreSQL statement
-through the ordinary execution API, but it does not make the in-process runtime
-crash-isolated.
-
-React Native uses TurboModule calls for lifecycle and configuration and JSI
-`ArrayBuffer` transport for buffered raw protocol bytes. Its host functions
-return promises and delegate runtime work to the same native owner used by the
-Swift or Kotlin SDK. Invalidation schedules close asynchronously instead of
-blocking the JavaScript, iOS main, or Android UI thread.
+Run schema setup before screens depend on it. Use parameterized queries, keep transactions short, and keep network requests and user interaction outside transaction callbacks.
## Broker mode
-The broker implementation targets iOS 26+ and Android API 24+. Apple compilation,
-signing, installed-worker lifecycle, and device file-protection qualification
-must pass before this is advertised as a supported release configuration.
-
-| Contract | iOS | Android |
-| --- | --- | --- |
-| Worker | Ordinary non-UI ExtensionFoundation app extension | Unexported bound service in `:oliphaunt` |
-| Control | Native XPC session | Native AIDL/Binder |
-| Database bytes | One Unix socket pair | One Unix socket pair |
-| Named storage | Extension-private Application Support | `noBackupFilesDir/Oliphaunt/` |
-| App integration | Signed embedded extension target | SDK manifest; guard app initialization in the worker |
-
-There is one active broker handle per application. A duplicate open fails;
-there is no hidden pool, automatic reconnection, or SQL replay. The mobile broker
-does not expose a listening server or independent client sessions. Worker loss
-makes the handle unusable: close it, open explicitly, and let PostgreSQL recover
-committed storage through WAL. Never blindly retry an operation with an unknown
-execution outcome.
+Choose broker mode when the database should run in a separate process. It keeps the same query and transaction API. Android supports it on API 24+; iOS requires iOS 26+, Xcode 26+, and an embedded, signed extension. The quickstarts use direct mode by default.
+
+Broker storage accepts an application-data name or temporary storage. Arbitrary directory paths are not supported. Keep one mobile broker handle open at a time; close it before opening or restoring another database.
### Swift
-The app target links `OliphauntBroker`. The worker target links
-`OliphauntBrokerExtension`, its selected seed/ICU resources, and extension products.
-Keep PostgreSQL and its resource products in the worker target. Use the SDK's
-`Templates/OliphauntBroker` source, plist, and build settings to create and sign
-that target. Compile the host declaration template in the app target and enable
-`EX_ENABLE_EXTENSION_POINT_GENERATION` there as well. Its default bundle identifier is the app identifier plus
-`.OliphauntBroker`; the app's `OliphauntBrokerExtensionBundleIdentifier` Info.plist
-key can name another embedded target.
+Add the `OliphauntBroker` product to your app and set up the worker using the [iOS broker target templates](https://github.com/f0rr0/oliphaunt/tree/main/src/native/sdks/swift/Templates/OliphauntBroker). Follow all target, embedding, and signing steps. Link the initialization seed and selected extension resources to the worker target.
```swift
import OliphauntBroker
-let db = try await OliphauntBroker.open(
- configuration: .init(storage: .applicationData(name: "primary")),
- options: .init(operationTimeout: .seconds(10))
-)
-let result = try await db.query("SELECT 42 AS answer")
-try await db.backup(to: archiveURL)
-try await db.close()
-try await OliphauntBroker.restore(storage: .applicationData(name: "restored"), from: archiveURL)
+@available(iOS 26, *)
+func openDatabase() async throws -> OliphauntDatabase {
+ try await OliphauntBroker.open(
+ configuration: .init(storage: .applicationData(name: "main")),
+ options: .init(startupTimeout: .seconds(30), operationTimeout: .seconds(10))
+ )
+}
```
-Pass selected generated extension resources to `OliphauntBrokerExtensionPeer` in
-the worker template. In the host, select their SQL identities with
-`OliphauntExtension(sqlName:)`; importing resource products into the host would
-also link their direct-runtime dependencies there.
+For backup, use `try await db.backup(to: archiveURL)` with a new app-owned file URL. After closing the handle, restore with `OliphauntBroker.restore(storage: .applicationData(name: "restored"), from: archiveURL)`. Reopen through `OliphauntBroker.open` with the same required extensions.
### Kotlin
+The Android SDK includes the broker service. In your existing `Application.onCreate`, return after `super.onCreate()` when `OliphauntBroker.isWorkerProcess(this)` is true. This avoids initializing UI frameworks and app services in the database process.
+
```kotlin
val db = OliphauntBroker.open(
- context,
- OliphauntConfig(storage = DatabaseStorage.ApplicationData("primary")),
+ context.applicationContext,
+ OliphauntConfig(storage = DatabaseStorage.ApplicationData("main")),
OliphauntBrokerOptions(operationTimeoutMillis = 10_000),
)
-val result = db.query("SELECT 42 AS answer")
-db.backup(archiveFile)
-db.close()
-OliphauntBroker.restore(context, DatabaseStorage.ApplicationData("restored"), archiveFile)
```
-Android creates your `Application` in the worker too. After `super.onCreate()`,
-return early when `OliphauntBroker.isWorkerProcess(this)` is true, before starting
-React Native, analytics, or other app initialization. Process-specific content
-providers also need app-owned configuration if they perform unrelated startup
-work. The service is private to the application's UID and is not a foreground
-service.
-
-### React Native and Expo
-
-Select `topology: 'broker'` once in the Expo plugin. Both platforms use that
-native build choice for every `open()` and `restore()` call. The plugin defaults
-the iOS minimum to 26.0, preserves a higher minimum, and rejects an explicitly
-lower one. It creates the worker target, declares its EAS signing identity,
-places runtime resources in the worker, and adds the Android `Application`
-guard. Repeated prebuilds are idempotent. Use `npx expo prebuild --clean` when
-switching topology.
-
-Install one seed package for fresh creation, such as
-`@oliphaunt/seed-native-ios-datum64-standard`; the plugin discovers its profile
-and version for both platforms. `open()` initializes new databases automatically.
-If both seed profiles are installed, select `seedProfile` explicitly.
-Android-only apps can select it without installing the iOS seed package.
-
-```json
+Import `dev.oliphaunt.*` and call this from a coroutine. Use the quickstart's Gradle seed selection for a new database. `db.backup(archiveFile)` writes a new backup file. After close, call `OliphauntBroker.restore(context, DatabaseStorage.ApplicationData("restored"), archiveFile)`, then reopen through the broker.
+
+### React Native
+
+Select the mode in the Expo plugin and rebuild the native app. For iOS, set your app's bundle identifier and deployment target:
+
+```json title="app.json"
{
"expo": {
- "ios": { "bundleIdentifier": "com.example.app" },
+ "ios": {
+ "bundleIdentifier": "com.example.notes",
+ "deploymentTarget": "26.0"
+ },
"plugins": [["@oliphaunt/react-native", { "topology": "broker" }]]
}
}
```
-```typescript
-import Oliphaunt, { applicationData } from '@oliphaunt/react-native';
+The plugin configures the iOS worker target and Android worker initialization. Keep the seed dependency from the quickstart. Sign the app and worker with your development team, then run `npx expo run:ios` or `npx expo run:android`.
+```ts
const db = await Oliphaunt.open({
- storage: applicationData('primary'),
- broker: { operationTimeoutMs: 10_000 }, // Optional.
+ storage: { kind: 'applicationData', name: 'main' },
+ broker: { startupTimeoutMs: 30_000, operationTimeoutMs: 10_000 },
});
-const backup = await db.backup();
-await db.close();
-await Oliphaunt.restore(applicationData('restored'), backup);
```
-The plugin entry remains necessary because adding and signing an iOS extension
-is a native build operation. JavaScript cannot create that target at runtime.
-Bare React Native builds select `OLIPHAUNT_REACT_NATIVE_TOPOLOGY=broker` for
-CocoaPods and `oliphauntTopology=broker` in Android's `gradle.properties`, and
-must perform the worker target and application setup described above.
-
-The native Swift/Kotlin file APIs stream archive bytes. React Native's existing
-`Uint8Array` backup/restore API remains buffered in the caller; the worker
-transport does not impose a total archive-size limit.
-
-### Deadlines and failures
-
-Startup defaults to 30 seconds. The optional operation timeout is disabled by
-default. When set, it includes queue admission, transport, and execution, using
-platform clocks that include device suspension. Cancellation is cooperative;
-if the operation does not settle within the private three-second grace period,
-the worker retires. Close uses the same bounded retirement path. The operating
-system can suspend or kill either process; a deadline is not a promise that code
-will run while the application is suspended.
-
-Swift `OliphauntBrokerError`, Kotlin `OliphauntBrokerException`, and React Native
-broker errors expose `reason`, `execution`, and `requiresReopen` independently.
-Execution is `notStarted`, `completed`, or `unknown`. A rejected queued request
-can leave the handle usable; an unknown execution outcome requires reopening.
-`completed` is not a retry-safety guarantee. Ordinary PostgreSQL errors retain
-SQLSTATE and transaction semantics, including `57014` after a recovered cancel.
-
-Raw operations accept one Simple Query or one extended group ending in Sync.
-SQL input is bounded at 128 MiB. COPY output may be streamed; interactive COPY
-input is rejected and drained to PostgreSQL readiness, or the worker is retired
-if recovery cannot be proven. Stream chunks are provisional until the operation
-settles. Callbacks must return synchronously and must not reenter the database;
-a stuck application callback cannot be forcibly unwound by a worker deadline.
-
-### Storage and migration
-
-Broker storage is a portable application-data name or temporary storage; arbitrary
-directory paths are rejected. iOS uses CompleteUntilFirstUserAuthentication
-protection and excludes the storage parent from backup. Android uses private
-no-backup storage. Native fresh creation still needs an explicit compatible seed;
-existing databases and physical restore do not need that seed.
-
-A same-name direct database causes `migrationRequired` before a fresh broker
-root is created. Export the direct database, close it, then explicitly restore
-into broker storage. The direct source is preserved. Restore requires an absent
-or empty destination and publishes the managed descriptor last. There are no
-App Groups, implicit copies, or automatic destructive migrations.
+Use the usual `backup`, `restore`, and query methods. Do not pass `topology` to `open`; the native build selects it. Omitting `operationTimeoutMs` leaves operations without an SDK deadline.
+
+### Recover from a broker failure
+
+Inspect `requiresReopen` on the broker error. When true, close the handle and reopen persistent storage explicitly. Check `execution`: `notStarted` means the request did not run; `unknown` means it may have changed data. Check your application state before retrying an unknown write. A deadline does not prove that a transaction rolled back.
+
+Direct and broker databases have separate storage locations. To migrate, back up through the original mode, close it, and restore into a fresh destination through the new mode. Do not switch modes and assume the same name opens the same files.
+
+## Handle suspension and termination
+
+Finish important writes while the app has execution time. An operating system can terminate a background app without waiting for a close callback. Persist throughout the session and use explicit close for orderly teardown.
+
+Cancel long-running work when the user leaves the operation that requested it. Cancellation can interrupt a statement; it does not replace rollback or close. Await transaction settlement before reporting that a write was cancelled.
+
+If an operation fails after the connection or process is lost, its outcome can be unknown. Use application-level identifiers and check whether the write already happened before retrying it.
+
+## Package extensions before building
+
+Selecting an extension changes native resources in your app. Configure the platform package or React Native plugin, rebuild the application, and then request the extension when opening the database. A JavaScript-only update cannot add a missing native extension.
+
+Use the [extension catalog](/docs/reference/extension-catalog) to check availability. Test the installed app on each target architecture with the selected extensions.
+
+## Exercise recovery
+
+Before release, test a persistent database across app restarts, an interrupted write, a failed transaction, a backup restored to a fresh destination, and an application upgrade. Confirm that the restored app ships the extensions its database needs.
diff --git a/src/docs/content/learn/native-runtime.mdx b/src/docs/content/learn/native-runtime.mdx
index 52aefe50e..bb8a38a5f 100644
--- a/src/docs/content/learn/native-runtime.mdx
+++ b/src/docs/content/learn/native-runtime.mdx
@@ -1,82 +1,40 @@
---
-title: Native Runtime
-description: Direct, broker, and server runtime behavior for native Oliphaunt SDKs.
+title: Choose a native runtime mode
+description: Choose direct embedding, process isolation, or a local server for your application.
---
-# Native Runtime
+Native Rust and desktop TypeScript offer three runtime modes. Swift, Kotlin, and React Native also offer mobile broker integration. Choose a mode based on process isolation and the number of database sessions your application needs.
-The native SDK family shares PostgreSQL 18 through `liboliphaunt`. Rust WASIX
-and WASIX TypeScript are separate products documented under
-[`WASIX`](/docs/sdk/wasix-rust).
+| Mode | Database runs in | Access | Choose it when |
+| --- | --- | --- | --- |
+| Direct | Your application process | SDK query handle, one session | You want embedded queries with the fewest moving parts |
+| Broker | A helper process | SDK query handle, one session | You need to isolate database execution from your app process |
+| Server | A server process | PostgreSQL connection string | You need a driver, ORM, pool, or independent sessions |
-## Choose a mode
+## Direct
-
+Direct mode is the default. The SDK manages a resident native backend in the application process. Keep one application-owned database handle and share it according to your language's concurrency rules.
-- Native direct embeds one process-resident PostgreSQL backend and one
- serialized physical session. It is the lowest-overhead path.
-- Native broker runs the same direct boundary in an SDK-owned helper process.
- It adds isolation and lets desktop applications own several instances.
-- Native server starts packaged PostgreSQL and exposes a connection string for
- pools, ORMs, tools, and independent client sessions.
+The first successful direct open binds the process to that root and configuration. Closing the handle releases the logical session; it does not unload PostgreSQL or let the process switch roots. Reopen the same root with compatible settings, or use broker/server mode for multiple roots. In direct mode, mobile apps switch to restored data on a subsequent process launch.
-Direct and broker SDK handle clones share one executor and one session.
-Transactions reserve that session. Server mode uses ordinary PostgreSQL client
-session semantics.
+In Rust, the synchronous handle blocks the calling thread. Use `AsyncOliphaunt` for async tasks. Swift, Kotlin, and JavaScript expose async APIs; those APIs serialize database work rather than creating a session per call.
-## Storage
+## Broker
-Native defaults to an SDK-owned temporary directory. Persistent storage is an
-explicit application-owned managed root with `.oliphaunt.json` and `pgdata`.
-Native does not label a temporary directory as memory storage.
+Broker mode moves execution into a helper process while retaining the SDK query API. It is available in native Rust and desktop TypeScript, and through platform-specific setup on iOS 26+ and Android. See [mobile broker setup](/docs/learn/mobile-stability#broker-mode).
-In the development checkout, desktop SDKs initialize new roots with initdb or an
-explicitly selected seed from the independent database-resources product, then
-publish the descriptor last. Mobile applications select their platform resource
-carrier. These resource-package changes are unreleased; completed releases retain
-their packaged initialization behavior. The low-level C runtime only validates a complete managed root; it never
-runs `initdb`, adopts raw PGDATA, or creates a descriptor during open.
+If the helper exits unexpectedly, the database handle becomes unusable. Close it and open a new handle on the same persistent directory. PostgreSQL recovers committed data from WAL. The SDK does not replay a failed operation, because its commit outcome may be unknown.
-Application-owned storage survives close. A direct close may detach the logical
-SDK owner while PostgreSQL remains resident in the process. Crash recovery is
-normal PostgreSQL WAL recovery on the next process launch. Use broker or server
-when the application process must survive a database-process failure.
+Package the helper executable and runtime resources with your app. Use the package's normal resource resolution unless your deployment layout requires an explicit path.
-## Startup configuration
+## Server
-Choose username, database, and validated PostgreSQL startup GUCs before open.
-Later GUC values win, matching PostgreSQL command-line behavior. There are no
-runtime-footprint or durability profile enums; tune the PostgreSQL settings the
-application actually needs.
+Server mode returns a lifecycle handle with a PostgreSQL connection string. Connect with a PostgreSQL driver or ORM to run queries; the server handle itself does not provide the embedded query API.
-## Backup and restore
+Keep the server handle alive for as long as clients use it. At shutdown, stop accepting application work, close client connections and pools, then close the server. A copied connection string does not keep the server running.
-Direct and broker expose one native PostgreSQL 18 physical backup. Mobile
-direct SDKs reach the same C implementation. Static restore accepts a new or
-existing-empty managed-root destination and never replaces nonempty data.
+See [Rust runtime recipes](/docs/sdk/rust/guide#choose-a-runtime-mode) or [TypeScript runtime recipes](/docs/sdk/typescript/guide#choose-a-runtime-mode). For a desktop webview, see [Use with Tauri](/docs/learn/tauri).
-Native server SDK backup is not currently exposed. Server applications use
-normal PostgreSQL tooling such as `pg_basebackup` or logical `pg_dump` where
-appropriate. Logical dump/restore is also the portable path across PostgreSQL
-versions and between native and WASIX families.
+## WASIX endpoints
-Use the server handle's `connection_string()` in Rust or `connectionString` in
-TypeScript with PostgreSQL's standard streamed-WAL command:
-
-```sh
-pg_basebackup --dbname "$CONNECTION_STRING" --pgdata ./server-backup --wal-method=stream
-```
-
-## Extensions
-
-Select exact extensions before open and enable them with standard PostgreSQL
-SQL. Desktop modes use packaged dynamic modules; mobile direct builds register
-selected static modules. Reopening a database requires the receiving runtime to
-carry the extensions already installed in its catalog.
-
-## Fixed support
-
-Runtime support is documented in the [static matrix](/docs/reference/capabilities).
-SDKs expose operations directly rather than returning a capability report.
-Unsupported mode operations return a clear error and never fall back to another
-runtime.
+WASIX SDKs have their own local endpoint on socket-capable hosts. It serves one connected client at a time; it is not a replacement for a native server with independent sessions. Browser apps do not expose a TCP listener.
diff --git a/src/docs/content/learn/sqlite-upgrade.mdx b/src/docs/content/learn/sqlite-upgrade.mdx
index 1c6f81dec..ab4b9d412 100644
--- a/src/docs/content/learn/sqlite-upgrade.mdx
+++ b/src/docs/content/learn/sqlite-upgrade.mdx
@@ -1,70 +1,60 @@
---
-sidebar_position: 1
-title: Moving From SQLite
-description: Map SQLite storage, SQL, backup, and extension assumptions to embedded PostgreSQL.
+title: Moving from SQLite
+description: Port SQLite schemas, queries, and persistence to embedded PostgreSQL.
---
-# Moving From SQLite
+Use this guide when your app needs PostgreSQL types, queries, or extensions and currently stores data in SQLite. Oliphaunt opens PostgreSQL storage; it does not open an existing SQLite database file.
-Oliphaunt is embedded PostgreSQL, so migration from SQLite starts by mapping a
-single-file database model to PostgreSQL directory storage, WAL, extensions, and PostgreSQL
-SQL semantics.
+## Compare the storage and SQL model
-Use this guide when an app already uses SQLite and you are evaluating whether a
-PostgreSQL-compatible embedded runtime is worth the extra footprint.
+| SQLite assumption | PostgreSQL equivalent |
+| --- | --- |
+| One database file | A managed directory or an explicit WASIX storage provider |
+| `?` query parameters | `$1`, `$2`, and subsequent parameters |
+| Flexible column typing | Declared PostgreSQL types and explicit casts |
+| `INTEGER PRIMARY KEY` row IDs | An identity column or an application-generated key |
+| `PRAGMA` configuration | PostgreSQL startup or session settings |
+| Load an extension library | Package/select the extension, then `CREATE EXTENSION` |
+| Copy a database file | Use SDK backup and restore |
-
+## Port a small schema first
-## Concept Map
+Create a disposable Oliphaunt database and port one table. For example, use an identity column for generated IDs and a PostgreSQL timestamp for creation time:
-| SQLite concept | Oliphaunt concept |
-| --- | --- |
-| One database file | One PostgreSQL storage directory |
-| Pragmas | PostgreSQL startup and session settings (GUCs) |
-| SQLite transaction | PostgreSQL transaction |
-| SQLite extension loading | Exact PostgreSQL extension selection before open |
-| File copy backup | SDK backup/export API |
-| Multiple library handles | Database sessions or the native server product |
-
-## Schema And SQL Differences
-
-PostgreSQL is stricter and richer than SQLite:
-
-- column types and casts matter more;
-- `SERIAL`, `IDENTITY`, sequences, arrays, JSONB, and enums replace many
- SQLite-specific conventions;
-- PostgreSQL query parameters are `$1`, `$2`, and so on;
-- constraints, indexes, and generated columns follow PostgreSQL syntax;
-- extension-backed types and operators require exact extension selection.
-
-Start with a small schema slice. Port table definitions, then migrate one query
-path at a time so type and constraint differences are visible early.
-
-## Storage And Backup
-
-SQLite apps often back up by copying one file. Oliphaunt live storage is a
-PostgreSQL directory, so data movement goes through SDK backup and restore
-APIs. Backup coordinates PostgreSQL online-backup state and required WAL.
-Restore validates one fixed physical archive and publishes a new managed root.
-Required extension code is still selected and packaged separately with the app.
-
-For mobile apps, keep persistent database storage app-private and use the platform's
-normal user-data protection choices. For desktop apps, choose direct, broker, or
-server mode based on the concurrency and process-isolation model your app needs.
-
-## Migration Path
-
-1. Choose the SDK for the app target.
-2. Open an Oliphaunt database with temporary storage and port the schema.
-3. Port read paths before write-heavy sync/import paths.
-4. Add selected extensions explicitly.
-5. Add backup/restore and inspect the built app artifact before shipping.
-6. Compare app-start, first-query, memory, and built artifact size against the
- SQLite baseline.
-
-## When SQLite Is Still The Better Fit
-
-Use Oliphaunt when PostgreSQL compatibility, richer SQL, extensions, and
-server-compatible workflows are worth the larger runtime and directory storage
-model. Use SQLite when a tiny single-file dependency and SQLite-specific
-semantics are the better fit.
+```sql
+CREATE TABLE notes (
+ id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ body text NOT NULL,
+ created_at timestamptz NOT NULL DEFAULT now()
+);
+```
+
+Port the corresponding queries with parameters:
+
+```sql
+INSERT INTO notes (body) VALUES ($1) RETURNING id;
+SELECT id, body, created_at FROM notes ORDER BY created_at DESC;
+```
+
+Bind values through your SDK. Check its decoding rules for `bigint`, timestamps, JSON, arrays, and null values before changing application models.
+
+## Transfer application data
+
+1. Create the PostgreSQL schema in a new persistent database.
+2. Read records through your existing SQLite integration.
+3. Convert values to the PostgreSQL types you chose, including dates and booleans.
+4. Insert with parameterized queries in bounded transactions.
+5. Compare row counts and representative values, including nulls and large integers.
+6. Switch the app to the new storage only after validation succeeds.
+
+Keep the original SQLite database until migration is complete and recoverable. A SQLite file or SQL dump is not an Oliphaunt physical backup; PostgreSQL may reject SQLite-specific SQL in a dump.
+
+## Revisit concurrency and backups
+
+One embedded handle executes one session's work in order. Use a [native server](/docs/learn/native-runtime#server) if the app requires a PostgreSQL connection pool with independent sessions.
+
+Replace file-copy backup code with the SDK's backup and restore methods. Test restore to a new destination with the app's selected extensions.
+
+## Measure the tradeoff
+
+Compare startup time, first-query latency, memory, and installed size using your actual schema and workload. PostgreSQL adds capabilities and a larger runtime. SQLite remains a good choice when a small single-file database already meets your app's needs. See [Measure performance](/docs/reference/performance).
diff --git a/src/docs/content/learn/tauri.mdx b/src/docs/content/learn/tauri.mdx
index 50912ee31..6321473ac 100644
--- a/src/docs/content/learn/tauri.mdx
+++ b/src/docs/content/learn/tauri.mdx
@@ -1,117 +1,95 @@
---
-title: Tauri Usage
-description: Use the Rust SDK from Tauri state and expose app-specific database commands to the webview.
+title: Use with Tauri
+description: Keep the database in Rust application state and expose focused commands to your webview.
---
-# Tauri Usage
+Use the native [Rust SDK](/docs/sdk/rust) in a Tauri app. Keep the database in Rust state and expose application operations such as adding or searching notes to the webview.
-Use the Rust SDK from Tauri state. `oliphaunt` is the native SDK for Tauri and
-Rust desktop apps; it owns direct embedded mode, broker mode, and server mode
-over native PostgreSQL.
+Add the `oliphaunt` dependency to the Tauri Rust application as shown in the [Rust quickstart](/docs/sdk/rust). The SDK includes its matching runtime resources.
-WASIX bindings are separate products. Native Tauri apps start with the native
-Rust SDK unless they deliberately choose the Rust WASIX host.
+## Open persistent application storage
-
+Use `AsyncOliphaunt` so database work does not block Tauri's async executor. This helper opens a root beneath the application-data directory and prepares a table:
-## App Shape
+```rust
+use oliphaunt::{AsyncOliphaunt, DatabaseStorage};
+use std::path::PathBuf;
+
+struct AppDatabase(AsyncOliphaunt);
-Keep the database handle in Rust state and expose narrow Tauri commands to the
-webview. The webview calls app-specific commands such as `add_item` or
-`search_items`; Rust owns the storage directory, lock, runtime handle, lifecycle,
-and backup APIs.
+async fn open_database(app_data: PathBuf) -> oliphaunt::Result {
+ let db = AsyncOliphaunt::builder()
+ .storage(DatabaseStorage::Directory(app_data.join("postgres")))
+ .direct()
+ .open()
+ .await?;
+ db.execute("CREATE TABLE IF NOT EXISTS notes (body text NOT NULL)").await?;
+ Ok(db)
+}
+```
-| Need | Recommended mode |
-| --- | --- |
-| One embedded app database with lowest overhead | `.direct()` |
-| Multiple database instances or helper-process ownership | `.broker()` |
-| SQLx pools, ORMs, `psql`, or `pg_dump` | `OliphauntServer::builder().start()` |
+During your existing Tauri builder's setup, resolve the directory and register the handle:
-## Direct Topology In Async Rust State
+```rust
+use tauri::Manager;
-Use `oliphaunt::AsyncOliphaunt` with direct topology when async Tauri
-commands share application state. PostgreSQL runs on one package-owned thread,
-so its synchronous work does not monopolize Tauri's async executor:
+// Add this setup callback to your existing tauri::Builder.
+.setup(|app| {
+ let app_data = app.path().app_data_dir()?;
+ let db = tauri::async_runtime::block_on(open_database(app_data))?;
+ app.manage(AppDatabase(db));
+ Ok(())
+})
+```
-```rust,no_run
-use oliphaunt::{AsyncOliphaunt, DatabaseStorage};
-use tauri::State;
+## Expose application commands
-struct Db(AsyncOliphaunt);
+Use managed state in an async command, bind user values, and register the command with `tauri::generate_handler![add_note]`:
+```rust
#[tauri::command]
-async fn add_item(db: State<'_, Db>, value: String) -> Result<(), String> {
- db.0
- .execute_with_params("INSERT INTO items(value) VALUES ($1)", [value])
+async fn add_note(
+ db: tauri::State<'_, AppDatabase>,
+ body: String,
+) -> Result<(), String> {
+ db.0.execute_with_params("INSERT INTO notes (body) VALUES ($1)", [body])
.await
- .map_err(|err| err.to_string())?;
+ .map_err(|error| error.to_string())?;
Ok(())
}
```
-Open the database under your app data directory during setup:
+The webview calls the command through Tauri:
-```rust,no_run
-use oliphaunt::{AsyncOliphaunt, DatabaseStorage};
+```ts
+import { invoke } from '@tauri-apps/api/core';
-async fn open_app_database(app_data_dir: std::path::PathBuf) -> oliphaunt::Result {
- AsyncOliphaunt::builder()
- .storage(DatabaseStorage::Directory(app_data_dir.join("postgres")))
- .direct()
- .open()
- .await
-}
+await invoke('add_note', { body: 'First note' });
```
-Store the resulting async handle with `tauri::State`. Its clones share one FIFO
-owner thread and one PostgreSQL session. The synchronous crate-root
-`oliphaunt::Oliphaunt` is `Send + !Sync`: it may move between threads but blocks
-the thread making each call and requires exclusive `&mut` access. Use it from a
-synchronous command or application-owned database thread, not directly on an
-async executor thread. Server mode is the path for independent PostgreSQL
-client sessions.
+Validate inputs and expose only operations the frontend needs. Keep database paths and raw SQL out of the frontend command contract.
-## Existing Postgres Clients
+## Use a PostgreSQL driver or ORM
-Use the dedicated server builder when another Rust library expects a PostgreSQL
-URL, real independent sessions, SQLx pools, `psql`, or `pg_dump`:
+If your Rust integration expects a connection URL and independent sessions, start an `AsyncOliphauntServer`. Return and retain the server handle, not only its URL:
-```rust,no_run
-use oliphaunt::{AsyncOliphauntServer, DatabaseStorage};
+```rust
+use oliphaunt::AsyncOliphauntServer;
-async fn start_server_mode() -> oliphaunt::Result {
- let server = AsyncOliphauntServer::builder()
- .storage(DatabaseStorage::Directory("./.liboliphaunt".into()))
+async fn start_server(app_data: PathBuf) -> oliphaunt::Result {
+ AsyncOliphauntServer::builder()
+ .storage(DatabaseStorage::Directory(app_data.join("postgres")))
.start()
- .await?;
-
- Ok(server.connection_string().to_owned())
+ .await
}
```
-Use `.broker()` for desktop apps that want helper-process ownership or
-multiple database instances managed by the Rust SDK.
-
-## Extensions And Assets
-
-Select exact SQL extension names in Rust configuration before opening the database.
-Package only the extension artifacts your Tauri app uses, then verify the app
-artifact before release. An app that selects `vector` ships `vector` and its
-declared dependencies.
+Store the server alongside the application's driver or pool. Create the pool using `server.connection_string()`. During shutdown, close the pool before awaiting `server.close()`.
-## Backup And Restore
+## Package and shut down
-Direct and broker databases expose one byte physical-backup API and static
-restore into an absent or empty destination. Local server handles intentionally
-omit SDK backup: use ordinary PostgreSQL `pg_basebackup` for physical backups or
-plain `pg_dump`/`psql` for logical workflows through the connection string.
+Ship the native runtime and any selected extensions with each desktop build. Test the packaged application; a development run may resolve files that are absent from the final bundle.
-## Operational Guidance
+Stop accepting application work before closing the database. Await `db.close()` through your app's shutdown path to observe errors. Use the SDK's backup API for direct/broker storage and PostgreSQL tools for server workflows.
-- Use `.direct()` for one embedded PostgreSQL session with minimal overhead.
-- Use `.broker()` when helper-process ownership matters more than direct
- call overhead.
-- Use `OliphauntServer::builder().start()` for real concurrent PostgreSQL client
- sessions and pools; the lifecycle handle itself does not execute SQL.
-- React Native apps use the React Native SDK, which delegates to Swift on
- iOS/macOS and Kotlin on Android.
+See Tauri's [state management](https://v2.tauri.app/develop/state-management/) and [calling Rust](https://v2.tauri.app/develop/calling-rust/) documentation for application wiring.
diff --git a/src/docs/content/reference/api-reference.mdx b/src/docs/content/reference/api-reference.mdx
index 4a18bfca6..5446da2bf 100644
--- a/src/docs/content/reference/api-reference.mdx
+++ b/src/docs/content/reference/api-reference.mdx
@@ -1,12 +1,17 @@
-# SDK API maps
+---
+title: API reference
+description: Find methods, configuration, results, and errors for your SDK.
+---
-These handwritten guides summarize each SDK. Generated API documentation is not currently published.
+Choose your language to look up the API. Each reference links to a guide with query, transaction, and backup examples.
-- [rust](/docs/sdk/rust/api-reference)
-- [swift](/docs/sdk/swift/api-reference)
-- [kotlin](/docs/sdk/kotlin/api-reference)
-- [react-native](/docs/sdk/react-native/api-reference)
-- [typescript](/docs/sdk/typescript/api-reference)
-- [wasix-rust](/docs/sdk/wasix-rust/api-reference)
-- [wasix-typescript](/docs/sdk/wasix-typescript/api-reference)
-- [c-abi](/docs/sdk/c-abi/api-reference)
+| SDK | Reference |
+| --- | --- |
+| Native Rust | [Types and methods](/docs/sdk/rust/api-reference) |
+| Native TypeScript | [Imports and configuration](/docs/sdk/typescript/api-reference) |
+| Swift | [Actors, configuration, and errors](/docs/sdk/swift/api-reference) |
+| Kotlin | [Coroutine APIs and typed results](/docs/sdk/kotlin/api-reference) |
+| React Native | [Storage, queries, and lifecycle](/docs/sdk/react-native/api-reference) |
+| WASIX Rust | [Builders, queries, and tools](/docs/sdk/wasix-rust/api-reference) |
+| WASIX TypeScript | [Host imports and storage adapters](/docs/sdk/wasix-typescript/api-reference) |
+| C / C++ | [C ABI types and functions](/docs/sdk/c-abi/api-reference) |
diff --git a/src/docs/content/reference/capabilities.mdx b/src/docs/content/reference/capabilities.mdx
index 0e8367716..9d6a24df0 100644
--- a/src/docs/content/reference/capabilities.mdx
+++ b/src/docs/content/reference/capabilities.mdx
@@ -1,61 +1,46 @@
---
-title: Runtime Support
-description: Static support matrix for native SDK modes, Rust WASIX, and WASIX TypeScript.
+title: Runtime support
+description: Compare storage, concurrency, backup, and tool support across Oliphaunt SDKs.
---
-# Runtime Support
+The SDKs share PostgreSQL semantics but differ in runtime integration. Use this table to check a requirement before choosing a package.
-Choose a product by its documented runtime contract. Support is intentionally a
-static product fact, not a capability-reporting API that every application must
-query after open.
+| Capability | Native SDKs | WASIX Rust | WASIX TypeScript |
+| --- | --- | --- | --- |
+| Default storage | Temporary directory | Memory filesystem | Memory filesystem |
+| Persistent storage | Directory or application-data name, depending on SDK and mode | Managed directory | IndexedDB/OPFS in browsers; directory on desktop |
+| Parameterized queries | Yes | Yes | Yes |
+| Callback transactions | Yes | Yes | Yes |
+| Raw response streaming | Yes | Yes | Yes |
+| Direct-query cancellation | Yes | No public API | No public API |
+| Physical backup and restore | Direct and broker handles | Yes | Yes; restore to persistent storage |
+| Broker process | Rust, desktop TypeScript, iOS 26+, and Android | No | No |
+| Local PostgreSQL endpoint | Rust and desktop TypeScript | One connected client | Desktop `/server`, one connected client |
+| Independent client sessions | Native server only | No | No |
+| Logical dump and SQL import | Optional endpoint tools | Optional `tools` feature | Optional tools package |
-
+The C ABI is a low-level binding interface and does not expose every high-level SDK helper. See its [API reference](/docs/sdk/c-abi/api-reference).
-## Products
+## Supported native platforms
-| SDK | Package | Hosts |
-| --- | --- | --- |
-| C ABI | `liboliphaunt` | Native direct binding boundary |
-| Rust | `oliphaunt` | Native direct, broker, server |
-| Swift | `Oliphaunt` | Native direct on iOS and macOS |
-| Kotlin | `dev.oliphaunt:oliphaunt-android` | Native direct on Android |
-| React Native | `@oliphaunt/react-native` | Swift/Kotlin direct adapters |
-| TypeScript | `@oliphaunt/ts` | Native direct, broker, server on supported desktop runtimes |
-| Rust WASIX | `oliphaunt-wasix` | WASIX direct and local server |
-| WASIX TypeScript | `@oliphaunt/wasix-ts` | Caller-realm browser Wasmer; native-host Node-API Rust-owner root, explicit `/direct`, and JavaScript `/worker` isolation |
+
-## Feature support
+These are the runtime package requirements. Your language runtime or app framework may impose a higher minimum. Use the [SDK quickstarts](/docs/sdk) for integration requirements.
-| Feature | Native SDK family | Rust WASIX | WASIX TypeScript |
-| --- | --- | --- | --- |
-| Default storage | SDK-owned temporary directory | Memory filesystem | Memory filesystem |
-| Persistent storage | Managed directory; React Native also resolves application-data names | Managed directory | IndexedDB/OPFS in browsers; managed directory on Node, Bun, Deno, and Electron |
-| Typed query and command helpers | Yes | Yes | Yes |
-| Raw PostgreSQL protocol | Buffered and callback-streamed | Buffered and callback-streamed; COPY uses the guest stream pump | Buffered and callback-streamed with bounded backpressure |
-| Callback transactions | Yes | Yes | Yes |
-| PostgreSQL `CHECKPOINT` SQL | Ordinary `execute` SQL; no SDK convenience method | Ordinary `execute` SQL; no SDK convenience method | Ordinary `execute` SQL followed by provider publication; no SDK convenience method |
-| Cancellation | Yes | No public direct-query cancellation | No public direct-query cancellation |
-| Dedicated COPY streaming | No | No | No |
-| Exact extension selection | SQL names | Typed Cargo selections | Selectively imported WASIX descriptors |
-| Physical backup/restore | Backup in direct/broker and mobile direct; static restore to new/empty storage | Yes | Backup from memory or persistent open sessions; static restore to a new or empty persistent provider |
-| Listening server | Rust and desktop TypeScript | Yes | One host-only `/server` subpath on Node, Bun, Deno, and Electron; no browser sockets |
-| `pg_dump` / `psql` | Optional endpoint-oriented `oliphaunt-tools` / `@oliphaunt/tools` products on Rust and desktop TypeScript | Optional open-database `tools` feature | Optional `@oliphaunt/wasix-tools` package on every host; `pgDump` supports root, direct, and Worker handles, while `psql` supports all three native placements or a browser Worker handle |
-| Independent client sessions | Native server only | No; the local endpoint accepts one connected client at a time | No |
-
-The native SDKs and both WASIX bindings expose callback raw-protocol response
-streaming. Typed query helpers remain buffered, and no dedicated typed COPY
-reader/writer API is promised.
-
-## Selection guidance
-
-Choose a native SDK when the application ships native runtime artifacts and
-wants direct, helper-process, or server integration. Choose Rust WASIX when a
-Rust host needs the portable runtime, optional local endpoint, or packaged
-tools. Choose WASIX TypeScript for browser Wasmer or Node/Bun/Deno/Electron WASIX Rust
-embedding with memory or explicit persistent providers; add its optional tools
-package or host-only `/server` subpath only when the application needs those
-capabilities.
-
-Native and WASIX packages never select or fall back to one another. Native and
-WASIX physical archives are family scoped; logical PostgreSQL dump/restore is
-the bridge between them.
+## Query and transaction behavior
+
+Typed query methods buffer their results. Raw response streaming is a PostgreSQL protocol interface, not a typed row stream or dedicated COPY reader/writer. Use it only when implementing a protocol-aware integration.
+
+Async APIs keep the calling application responsive; they do not give a single embedded database multiple concurrent sessions. Use the native server with a PostgreSQL driver for independent sessions.
+
+## PostgreSQL tools
+
+Native Rust and desktop TypeScript use the optional `oliphaunt-tools` or `@oliphaunt/tools` packages with a server connection string.
+
+WASIX Rust enables `pg_dump` and non-interactive `psql` with its `tools` Cargo feature. WASIX TypeScript uses `@oliphaunt/wasix-tools`: `pgDump` supports root, direct, and Worker handles; `psql` supports desktop placements and browser Worker handles. Browsers cannot open TCP listeners.
+
+## Data movement
+
+Physical backups require a compatible runtime within the same family. Use logical PostgreSQL dump/restore to move between native and WASIX. Install required extensions on the destination before importing data that depends on them.
+
+For persistence and packaging examples, use your [SDK guide](/docs/sdk). For mobile lifecycle decisions, see [Ship a mobile database](/docs/learn/mobile-stability).
diff --git a/src/docs/content/reference/extensions.mdx b/src/docs/content/reference/extensions.mdx
index 2dc8e027d..557f1517b 100644
--- a/src/docs/content/reference/extensions.mdx
+++ b/src/docs/content/reference/extensions.mdx
@@ -1,129 +1,52 @@
---
title: Extensions
-description: Select exact PostgreSQL extensions through each SDK's native API and verify the carriers that enter an app.
+description: Package a PostgreSQL extension, select it in your SDK, and enable it with SQL.
---
-# Extensions
+Extensions add PostgreSQL functionality such as vector search, spatial types, and additional operators. Find a supported SQL name in the [extension catalog](/docs/reference/extension-catalog).
-Oliphaunt uses exact, opt-in PostgreSQL extension selection. Native SDKs accept
-exact SQL names, Rust WASIX exposes exact Cargo features and typed values, and
-WASIX TypeScript accepts selectively imported portable descriptors. Browser
-artifacts contain only the selected extensions plus mandatory dependencies
-declared by extension metadata. The Node/Bun/Deno/Electron Node-API carrier embeds the
-qualified catalog once and validates each selected descriptor against those
-exact bytes.
+## Add an extension in three steps
-There are no extension packs, aliases, or grouped selectors. Selection remains
-exact even when a native carrier physically contains the full catalog.
+1. **Package it.** Include the extension resources and any required native code for your application target.
+2. **Select it before opening.** Use your SDK's configuration, typed value, or descriptor.
+3. **Enable it with SQL.** Run the extension's documented activation, usually `CREATE EXTENSION`.
-
+For example, after packaging and selecting `vector`:
-
-
-## Native selection
-
-Select extensions before opening the database:
-
-```rust
-use oliphaunt::{Extension, Oliphaunt};
-
-# fn demo() -> oliphaunt::Result<()> {
-let mut db = Oliphaunt::builder()
- .direct()
- .extension(Extension::VECTOR)
- .open()?;
-
-db.execute("CREATE EXTENSION vector")?;
-# Ok(())
-# }
+```sql
+CREATE EXTENSION IF NOT EXISTS vector;
+CREATE TABLE embeddings (id bigint PRIMARY KEY, embedding vector(3));
```
-`CREATE EXTENSION` succeeds when the selected runtime resources contain that
-extension for the target platform. The SDK loads only the selected extension
-artifacts and their declared dependencies.
-
-## Rust WASIX selection
+Selection makes an extension available; it does not run your schema migrations. Some catalog entries have different activation requirements, which the catalog records.
-Enable the exact extension feature and pass its typed value to the WASIX
-builder. The builder makes the artifact available; application migrations must
-still install database-local objects explicitly:
+## Follow your SDK's packaging path
-```toml
-[dependencies]
-oliphaunt-wasix = { version = "={{release:oliphaunt-wasix-rust}}", features = ["extension-pgtap"] }
-```
+| SDK | Packaging and selection |
+| --- | --- |
+| [Rust](/docs/sdk/rust/guide#select-extensions) | Native builder selection such as `oliphaunt_extension_vector::VECTOR` |
+| [Swift](/docs/sdk/swift/guide#add-an-extension) | Generate/link a Swift extension product and select its `.resource` |
+| [Kotlin](/docs/sdk/kotlin/guide#select-extensions) | Select in Gradle, rebuild, and select its `OliphauntExtension` value at open |
+| [React Native](/docs/sdk/react-native/guide#add-an-extension) | Install extension packages, configure the plugin, rebuild, and select at open |
+| [TypeScript](/docs/sdk/typescript/guide#select-extensions) | Install/import the native extension descriptor and pass it at open |
+| [WASIX Rust](/docs/sdk/wasix-rust/guide#select-extensions) | Add the extension crate with its `wasix` feature and select its typed value |
+| [WASIX TypeScript](/docs/sdk/wasix-typescript/guide#select-extensions) | Install/import the `-wasix` descriptor package and pass the descriptor |
+| [C ABI](/docs/sdk/c-abi/guide#register-extensions) | Link/register static modules and provide matching resources |
-```rust
-use oliphaunt_wasix::{Extension, Oliphaunt};
+Use exact SQL extension names. Selection can bring required dependencies with it; it does not select unrelated extensions through aliases or bundles.
-let mut database = Oliphaunt::builder().extension(Extension::PGTAP).open()?;
-database.execute("CREATE EXTENSION pgtap")?;
-```
+## Match runtime compatibility
-## WASIX TypeScript selection
+Native and WASIX extension packages are distinct. A package ending in `-wasix` supplies a WASIX descriptor; a native package cannot be substituted for it.
-Import only the portable descriptors the browser, Node, Bun, Deno, or Electron application uses:
+External extension package versions describe Oliphaunt packaging and can differ from the upstream PostgreSQL extension version. Match the package to its compatible Oliphaunt runtime rather than assuming equal version numbers mean compatibility.
-```ts
-import Oliphaunt from '@oliphaunt/wasix-ts';
-import pgtap from '@oliphaunt/extension-pgtap-wasix';
+Reopen an extension-bearing database with its required code and resources available. A database backup preserves extension objects and data, not the extension binaries in your app.
-const database = await Oliphaunt.open({ extensions: [pgtap] });
-```
+## Upgrade an extension
-The descriptor carries the exact dependency and compatibility metadata needed
-by the selected runtime owner. SQL-name strings are intentionally not accepted
-by this API. Use only extensions published for the selected WASIX host.
+Read the extension and runtime release notes, back up the database, update the compatible application resources, and apply any documented SQL migration. Do not assume opening a database automatically runs `ALTER EXTENSION ... UPDATE`.
-## Platform Behavior
+## Diagnose an unavailable extension
-| Platform | Expected behavior |
-| --- | --- |
-| Rust/Tauri desktop | SDK resolves selected runtime extension artifacts for the target |
-| iOS/macOS Swift | App bundle includes selected extension artifacts and dependencies only |
-| Android Kotlin | Android package includes selected extension artifacts and dependencies only |
-| React Native | Config plugin delegates selection to Swift/Kotlin packaging |
-| TypeScript | SDK resolves selected native artifacts or helper-process resources |
-| Rust WASIX | Exact Cargo features carry selected portable artifacts; typed values select them at open |
-| WASIX TypeScript | Selective `-wasix` imports carry exact descriptors and browser bytes; Node, Bun, Deno, and Electron validate those descriptors against extensions embedded in the matching Node-API carrier |
-
-## Dependencies
-
-Some PostgreSQL extensions depend on other extensions or runtime files. Those
-dependencies are explicit metadata. If `earthdistance` declares `cube` as a
-dependency, selecting `earthdistance` may include `cube`; selecting `vector`
-includes `vector` and its declared dependencies only.
-
-## External Extensions
-
-External extensions are distributed as exact extension artifacts or indexes.
-Native consumers select SQL names; WASIX consumers use the runtime-specific
-typed value or descriptor published for that extension.
-
-Each public external extension has its own product tag, changelog, and package
-version. The PostgreSQL contrib bundle is only a logical distribution: its
-native and WASIX carriers inherit the corresponding runtime product version.
-Exact compatibility metadata pins a consumer to a published dependency version
-without causing either product to release. External extension packages own
-independent packaging SemVer; their immutable upstream version/commit and
-compatible Oliphaunt runtime versions are separate metadata.
-Do not assume an external package version matches either its upstream project
-version or the runtime version.
-
-The WASIX carrier uses the explicit `-wasix` identifier while the native/default
-package keeps its existing name. Both carriers belong to the same extension
-product version stream; `-wasix` does not create an unrelated second extension
-release line.
-
-## Verifying App Artifacts
-
-Before release, app tooling reports:
-
-- selected SQL extension names;
-- included extension files;
-- mandatory dependencies;
-- package-size contribution per extension;
-- target platform and architecture.
-
-That report lets developers confirm that an app using only `vector` ships
-`vector` and its declared dependencies, without unrelated extension artifacts.
+Check the exact SQL name, target support, installed package, build-time selection, and open-time selection. For mobile apps, rebuild the native application after changing extensions. For a restored database, verify the destination app includes the original database's required extensions.
diff --git a/src/docs/content/reference/index.mdx b/src/docs/content/reference/index.mdx
index 3a953870a..96b8bc284 100644
--- a/src/docs/content/reference/index.mdx
+++ b/src/docs/content/reference/index.mdx
@@ -1,51 +1,17 @@
---
title: Reference
-description: Look up SDK support, runtime capabilities, extensions, releases, performance, and API surfaces.
+description: Look up SDK capabilities, extensions, versions, and API behavior.
---
-# Reference
-
-Reference pages answer product lookup questions. Use them when you already know
-the app target and need exact support, extension, package, release, or API
-details.
-
-
-
-## How To Use Reference
-
-
-
-
- ### Start with the app target
-
- Use [SDKs And Platforms](/docs/reference/sdk-products) to choose the package
- for the app users install: a native SDK, Rust WASIX, WASIX
- TypeScript, or the C ABI.
-
-
-
-
- ### Check runtime capability
-
- Use [Runtime Support](/docs/reference/capabilities) before enabling UI for
- broker, server, C-level protocol streaming, backup, restore, or independent client
- sessions.
-
-
-
-
- ### Select artifacts deliberately
-
- Use [Extensions](/docs/reference/extensions) and the generated catalog to
- package only the SQL extensions your app selects.
-
-
-
-
- ### Verify release fit
-
- Use [Performance](/docs/reference/performance), the published products page,
- and SDK API maps when preparing a release candidate.
-
-
-
+Use these pages to check a capability or find an API. If you are installing Oliphaunt for the first time, start with an [SDK quickstart](/docs/sdk).
+
+| Reference | What you can find |
+| --- | --- |
+| [SDKs and platforms](/docs/reference/sdk-products) | Package names and application targets |
+| [Runtime support](/docs/reference/capabilities) | Storage, concurrency, cancellation, and tools |
+| [Extensions](/docs/reference/extensions) | Selection and SQL activation |
+| [Extension catalog](/docs/reference/extension-catalog) | Available extensions and target support |
+| [API reference](/docs/reference/api-reference) | API pages for each language |
+| [Versions](/docs/reference/version-matrix) | SDK versions used in these examples |
+| [Releases and upgrades](/docs/reference/releases) | Choose a version and plan an upgrade |
+| [Measure performance](/docs/reference/performance) | Measure startup, queries, memory, and app size |
diff --git a/src/docs/content/reference/performance.mdx b/src/docs/content/reference/performance.mdx
index 4bf8a0dc5..80fdcf1b9 100644
--- a/src/docs/content/reference/performance.mdx
+++ b/src/docs/content/reference/performance.mdx
@@ -1,94 +1,54 @@
---
-title: Performance
-description: Understand the latency, throughput, memory, package-size, and SQLite comparison measurements Oliphaunt publishes.
+title: Measure performance
+description: Measure startup, query latency, memory, and installed size for your own application.
---
-# Performance
+Measure Oliphaunt with your schema, selected extensions, and target device.
-Oliphaunt is designed for app-embedded PostgreSQL. Performance work focuses on
-the operations developers feel in production apps: open time, simple-query
-latency, transaction throughput, bulk load speed, large result transfer,
-backup/restore time, memory footprint, and packaged app size.
+## Separate the costs
-
+| Measurement | Start and end points |
+| --- | --- |
+| First open | Before opening a new root → usable database handle |
+| Reopen | Before opening existing persistent storage → usable handle |
+| First query | Before submitting SQL → decoded result |
+| Steady-state query | The same query after initialization, over repeated runs |
+| Transaction | Before beginning → committed result |
+| Backup | Before requesting backup → complete returned archive |
+| App footprint | Installed application and resources, plus database storage |
-## What to measure
+Include storage initialization and extension activation when those happen during real startup. Measure packaged release builds; development builds and asset caches can change results.
-Use performance numbers in context:
+## Measure a query
-| Area | Why it matters |
-| --- | --- |
-| Cold open | App startup and first database access |
-| Warm open | Reopening a database during normal app use |
-| Query latency | UI responsiveness for small reads and writes |
-| Transaction throughput | Sync, import, and local-first write workloads |
-| Bulk load | Initial dataset import and cache hydration |
-| Large result transfer | Reports, sync scans, and export flows |
-| Backup and restore | User data migration and support workflows |
-| RSS and package size | Mobile distribution and desktop app footprint |
-
-Native direct mode is the lowest-latency embedded path. Broker mode adds
-an IPC boundary in exchange for process isolation and multi-instance management.
-Server mode is the right choice when an app needs real PostgreSQL client
-connections, tools, pools, or ORMs.
-
-## Compare modes honestly
-
-Compare each mode against the problem it solves:
-
-- Use direct mode when one embedded database session is enough and latency is
- the primary concern.
-- Use broker mode when crash isolation, explicit reopen recovery, upgrades, or
- multiple instances
- are more important than the last microseconds of latency.
-- Use server mode when independent PostgreSQL clients are part of the product.
-
-For mobile apps, include startup time, memory footprint, selected extensions,
-and app artifact size in the same report. The useful result is the one that
-keeps latency, throughput, memory, and selected-extension packaging visible
-together.
-
-## SQLite comparison
-
-SQLite is the baseline developers already trust for embedded storage. Oliphaunt
-is measured against SQLite for:
-
-- first query after app launch;
-- single-row lookup;
-- batched insert/update;
-- aggregate queries over realistic local datasets;
-- transaction cost;
-- package size and memory footprint.
-
-The comparison explains the workload and schema. PostgreSQL features such
-as extensions, SQL compatibility, data types, and server-mode interoperability
-are part of the value proposition alongside low latency, high throughput, and a
-bounded footprint in common app workloads.
-
-## Release Measurements
-
-Published performance results include:
-
-- hardware and operating system;
-- SDK and runtime mode;
-- PostgreSQL and Oliphaunt versions;
-- selected extensions;
-- repeat count and percentile method;
-- memory/RSS collection method;
-- package-size method;
-- links to reproducible benchmark workloads.
-
-Reports must show p50/p90/p95/p99 latency, suite totals, throughput, RSS,
-CPU time, package size, and benchmark provenance.
-
-Native Direct Regression Diagnostics are included when direct mode misses a
-gate, so the report links the failing suite back to repeatable diagnostic
-commands rather than only showing a red/green result.
-
-PostgreSQL configuration sweeps must stay inside valid server settings. For
-example, `min_wal_size=8MB` is the practical lower bound because values below a
-WAL segment are invalid PostgreSQL experiments, not useful mobile footprint
-tuning data.
-
-Public docs present stable methodology and release results. Raw run logs and
-benchmark debugging notes stay out of app-developer setup guides.
+With an open native TypeScript database, record the elapsed time around the complete awaited operation:
+
+```ts
+const started = performance.now();
+const result = await db.query('SELECT 42::int4 AS answer');
+const elapsedMs = performance.now() - started;
+console.log({ elapsedMs, answer: result.rows[0]?.answer });
+```
+
+Repeat measurements and report the median and a tail percentile alongside the sample count. Keep the device, runtime mode, schema, row count, SQL, parameter values, and extension selection constant when comparing runs.
+
+## Investigate slow SQL
+
+For an existing `notes(id, body)` table, use PostgreSQL's query planner with representative data:
+
+```sql
+EXPLAIN (ANALYZE, BUFFERS)
+SELECT id, body FROM notes WHERE id = 42;
+```
+
+`ANALYZE` executes the statement. Use a disposable copy for statements with side effects. Check indexes, row estimates, result size, and time spent decoding before changing runtime settings.
+
+Typed queries buffer results. Select only the columns you need and paginate large application reads. Batch related writes in bounded transactions instead of committing each row separately.
+
+## Compare runtime modes
+
+Direct, broker, and server modes have different process and connection costs. Measure the mode you will ship. For async integrations, measure UI responsiveness or executor delay separately from SQL latency.
+
+Browser persistence includes host-provider work. Compare memory and persistent storage only if you report that difference; an in-memory result does not predict durable write latency.
+
+When comparing with SQLite, include installed size and memory as well as query speed. See [Moving from SQLite](/docs/learn/sqlite-upgrade) for the integration differences.
diff --git a/src/docs/content/reference/releases.mdx b/src/docs/content/reference/releases.mdx
index 590a70475..4144e25fb 100644
--- a/src/docs/content/reference/releases.mdx
+++ b/src/docs/content/reference/releases.mdx
@@ -1,96 +1,31 @@
---
-sidebar_position: 1
-title: Releases
-description: Match SDK versions, runtime artifacts, selected extensions, release notes.
+title: Releases and upgrades
+description: Match documentation to your SDK version and plan database or extension upgrades.
---
-# Releases
+Oliphaunt SDKs and runtimes have independent versions. Use the [version table](/docs/reference/version-matrix) to see the package versions documented by this site, and the package's linked release notes for changes.
-Oliphaunt products are released independently. Start from the package your app
-installs, then check the runtime artifacts and selected extensions that package
-expects.
+## Match your dependency
-
+Install examples use the versions associated with this documentation build. Pin dependencies in your package manifest or lockfile so an application rebuild uses the versions you tested.
-The [published products](/docs/reference/version-matrix) page lists completed public releases. A product without a completed release is not available for installation.
+The SDK package selects compatible runtime dependencies. Keep those dependencies together instead of independently replacing a native library, WebAssembly runtime, or helper executable. React Native also depends on compatible Swift and Kotlin integrations.
-Unreleased checkout APIs are explicitly labelled in the guides. A development
-example using a new resource or socket package is not an installation promise.
-Published installation versions remain independent of those source changes.
+Extension packages have their own versions and runtime compatibility. A matching numeric version across unrelated products is not a compatibility guarantee.
-## Version Relationships
+## Upgrade an application
-| Relationship | Products | Rule |
-| --- | --- | --- |
-| Independently versioned | Native, WASIX, external extensions, SDKs, database resources, PostgreSQL tools, and socket adapters | Release Please selects changed product paths; each product owns its SemVer, and native and WASIX do not move together |
-| Runtime-owned distribution | PostgreSQL contrib | Native and WASIX carriers inherit their owning runtime's version; contrib has no independent release identity |
-| Exact compatibility | Products with dependency or runtime compatibility fields | The consumer declares its compatible product versions; release preparation propagates changed dependency pins to affected consumers |
-| Upstream-bound | External exact-extension products | Packaging SemVer is independent; immutable upstream version/commit and compatible runtime versions are recorded separately |
-| Documentation | Public documentation site | Guides and references can change without a package release |
+1. Read release notes for your SDK, its runtime changes, and selected extensions.
+2. Create a recoverable backup and test the upgrade against a copy of application data.
+3. Update the application dependency and its lockfile.
+4. Rebuild native applications when runtime resources or extensions change.
+5. Apply documented schema or extension migrations.
+6. Verify queries, transactions, restart recovery, and restore before switching user data.
-React Native spans two native platform SDKs. A JavaScript package release may
-need matching Swift and Kotlin artifacts even when the TypeScript API shape is
-unchanged.
+Use physical restore only when runtime-family and format compatibility are documented. Use logical dump/restore for incompatible formats or transfers between native and WASIX. See [WASIX dump and restore](/docs/sdk/wasix-rust/dump-restore) for an example.
-## Target Availability
+## Find the matching reference
-The first native desktop carriers cover Linux x64/arm64 GNU, macOS arm64, and
-Windows x64 MSVC. Android carriers cover `arm64-v8a` and `x86_64`. Apple uses
-the declared iOS XCFramework plus the macOS arm64 runtime carrier. WASIX ships a
-portable carrier and AOT carriers for the supported desktop hosts.
+Use [Versions](/docs/reference/version-matrix) to compare your dependencies with this documentation. For an older SDK, open its release tag to read the README shipped with that version. When reporting a docs issue, include your SDK version and the page URL.
-macOS x64, Windows ARM64, Linux musl, Android 32-bit, and undeclared Apple
-architectures are not first-release targets. Every extension on `main` supports
-the complete canonical target profile. Exact extension carrier metadata is
-generated from that shared profile; uncatalogued branch work has no release
-surface.
-
-### Consumer Compatibility Floors
-
-The release gate inspects staged binaries against the following contract. These
-are consumer compatibility floors, not merely the operating systems used to
-build the artifacts.
-
-{/* BEGIN GENERATED PLATFORM COMPATIBILITY */}
-| Published carrier | Enforced consumer compatibility contract |
-| --- | --- |
-| Linux x64/arm64 GNU | Required symbol versions do not exceed `GLIBC_2.38` or `GLIBCXX_3.4.30`. |
-| Direct macOS arm64 runtime | Minimum deployment target is macOS 11.0. |
-| Android `arm64-v8a` and `x86_64` | Minimum Android API level is 24; Android binaries must not require GLIBC/GLIBCXX symbol families. |
-| Apple XCFramework | Contains macOS arm64, iOS device arm64, and iOS Simulator arm64 slices; minimum targets are macOS 14.0, iOS 17.0, and iOS Simulator 17.0. |
-| Windows x64 MSVC | Requires the x64 PE/COFF contract and the declared app-local Visual C++ runtime profile; Windows ARM64 is not published. |
-{/* END GENERATED PLATFORM COMPATIBILITY */}
-
-The table is synchronized with the authoritative binary compatibility policy
-used by release staging. A carrier fails qualification when its inspected ELF,
-Mach-O, Android, or PE metadata exceeds this contract.
-
-### Mobile Package And Runtime Coverage
-
-Package availability and installed-app execution are separate support claims:
-
-| Surface | Built and binary-inspected release candidates | Required installed-app execution |
-| --- | --- | --- |
-| Android | Both `arm64-v8a` and `x86_64` runtime and exact-extension carriers, plus release APKs for both ABIs | The `x86_64` APK runs the full installed-app workload on the API 35 emulator. Android arm64 is not executed on a physical device in the required first-release gate. |
-| Apple | The XCFramework's macOS arm64, iOS device arm64, and iOS Simulator arm64 runtime and exact-extension slices | The iOS Simulator arm64 app runs the full installed-app workload. The iOS device arm64 slice is built and inspected, but is not installed or executed on a physical iOS device in the required first-release gate. |
-
-This boundary does not mean that Android arm64 or iOS device packages are
-absent. It distinguishes artifact construction and binary compatibility proof
-from hardware-specific execution coverage, so release notes state exactly which
-installed-app workloads are required for each platform.
-
-## What A Release Tells You
-
-Release notes answer these questions:
-
-- PostgreSQL baseline used by the runtime;
-- SDK packages published in the release;
-- platforms and architectures with artifacts;
-- exact SQL extensions available for each target;
-- direct, broker, server, buffered raw protocol, low-level C callback streaming,
- backup, and restore support;
-- migration or rebuild steps for app developers.
-
-## Documentation
-
-These guides describe the latest available products. Documentation fixes deploy from main independently of product releases. Completed releases refresh the installation versions displayed in these guides. Historical documentation versions are not maintained.
+See all [GitHub releases](https://github.com/f0rr0/oliphaunt/releases) for release notes and downloadable artifacts.
diff --git a/src/docs/content/reference/sdk-products.mdx b/src/docs/content/reference/sdk-products.mdx
index ab5dfeef5..070e3a5f3 100644
--- a/src/docs/content/reference/sdk-products.mdx
+++ b/src/docs/content/reference/sdk-products.mdx
@@ -1,73 +1,25 @@
---
-title: SDKs And Platforms
-description: Compare native SDKs, Rust WASIX, and WASIX TypeScript by package, host, storage, and responsibility.
+title: SDKs and platforms
+description: Compare package names, application targets, and default storage.
---
-# SDKs And Platforms
+Choose the package for your application's language and runtime. Native and WASIX packages are separate choices.
-Oliphaunt ships peer SDK products for the environments where developers build
-apps. The products share PostgreSQL semantics and exact release inputs while
-keeping public APIs native to each language and host.
-
-## Choose an SDK
-
-
-
-| Product | Public package | Runtime boundary | Default storage |
+| SDK | Package | Application targets | Default storage |
| --- | --- | --- | --- |
-| Rust | `oliphaunt` | Native direct, broker, or server | Temporary directory |
-| Swift | `Oliphaunt` | Native runtime through Swift concurrency | Temporary directory |
-| Kotlin | `dev.oliphaunt:oliphaunt-android` | Native runtime through coroutines | Temporary directory |
-| React Native | `@oliphaunt/react-native` | Swift/Kotlin native runtime through TurboModule/JSI | Platform SDK default |
-| TypeScript | `@oliphaunt/ts` | Native runtime or native helper process | Temporary directory |
-| Rust WASIX | `oliphaunt-wasix` | Rust-owned portable WASIX host | Memory filesystem |
-| WASIX TypeScript | `@oliphaunt/wasix-ts` | Browser Wasmer; Node/Bun/Deno/Electron Rust-owner root, explicit `/direct`, or `/worker` isolation | Memory filesystem |
-
-The existing native package and extension identifiers remain unchanged. WASIX
-is the explicit special-case identifier: for example,
-`@oliphaunt/extension-pgtap-wasix` is portable while
-`@oliphaunt/extension-pgtap` remains the native/default carrier.
-
-## Product Boundaries
-
-React Native delegates execution to the Swift and Kotlin SDKs. Native
-TypeScript owns Node.js, Bun, and Deno integration over native runtimes and
-helpers. WASIX TypeScript never imports that native package and does not silently
-change runtime families; its conditional exports select the browser Wasmer host
-or its own WASIX Rust Node-API host.
-
-The native TypeScript npm package carries native runtime integration for Node.js,
-Bun, and Deno. WASIX TypeScript is a separate npm product supporting every
-declared host, including its Deno directory-storage subpath.
-
-Rust WASIX and WASIX TypeScript are peer bindings over the WASIX runtime and
-physical archive contract. Browsers consume portable runtime/tool assets;
-Node, Bun, Deno, and Electron consume a platform Node-API carrier built from the same
-exact inputs. Both expose the same single-backend local-endpoint concept on
-socket-capable hosts and optional open-database `pg_dump`/non-interactive
-`psql`. TypeScript keeps sockets absent in browsers: `pgDump` supports root,
-direct, and Worker handles, while `psql` requires a browser Worker and supports
-all three native placements. The TypeScript binding also owns isolated host adapters, pgwire
-error recovery, callback-scoped transactions, and host-specific persistence
-(IndexedDB or OPFS in browsers, directories on Node/Bun/Deno/Electron). Shared concepts
-and carriers do not force identical host code or language signatures.
-
-## Cohesive Concepts
-
-- Use `storage` for database lifetime and persistence choices.
-- Select only exact extensions before opening a database.
-- Handle PostgreSQL failures through structured errors and SQLSTATE.
-- Close the owning handle explicitly; use the product's documented persistence
- or backup mechanism instead of copying live database files.
+| [Rust](/docs/sdk/rust) | `oliphaunt` | Native desktop, Tauri | Temporary directory |
+| [Swift](/docs/sdk/swift) | `Oliphaunt` | iOS, macOS | Temporary directory |
+| [Kotlin](/docs/sdk/kotlin) | `dev.oliphaunt:oliphaunt-android` | Android | Temporary directory |
+| [React Native](/docs/sdk/react-native) | `@oliphaunt/react-native` | iOS, Android | Temporary directory |
+| [TypeScript](/docs/sdk/typescript) | `@oliphaunt/ts` | Node.js, Bun, Deno, Electron | Temporary directory |
+| [WASIX Rust](/docs/sdk/wasix-rust) | `oliphaunt-wasix` | Rust hosts | Memory filesystem |
+| [WASIX TypeScript](/docs/sdk/wasix-typescript) | `@oliphaunt/wasix-ts` | Browser, Node.js, Bun, Deno, Electron | Memory filesystem |
+| [C ABI](/docs/sdk/c-abi) | `liboliphaunt` | Custom native bindings | Caller-prepared managed root |
-
+## Runtime differences
-## Extensions
+React Native uses the Swift and Kotlin native integrations. A Tauri app normally keeps its database in Rust and exposes application commands to the webview.
-
+Choose WASIX TypeScript when the same application needs browser and desktop storage adapters. Choose native TypeScript for native desktop runtime modes.
-Native SDKs select exact SQL extension names in ecosystem-native configuration.
-WASIX TypeScript imports only the `-wasix` descriptor packages it uses
-and passes those descriptors to `open()`. Rust WASIX uses exact Cargo features
-and typed extension values. These forms express the same packaging principle
-without forcing one language's API shape onto another.
+Use [Runtime support](/docs/reference/capabilities) to compare persistent storage, local endpoints, and optional tools. Each SDK quickstart describes its platform setup.
diff --git a/src/docs/content/sdk/c-abi/api-reference.md b/src/docs/content/sdk/c-abi/api-reference.md
index 855558c61..5a946f685 100644
--- a/src/docs/content/sdk/c-abi/api-reference.md
+++ b/src/docs/content/sdk/c-abi/api-reference.md
@@ -1,81 +1,66 @@
---
-title: API Reference
-description: C ABI API map for native runtime initialization, protocol execution, response ownership, and lifecycle.
+title: C ABI reference
+description: Configuration structs, query functions, buffers, errors, and lifecycle in oliphaunt.h.
---
-# API Reference
-
-This page maps the C ABI by
-task.
-
-| Area | Public surface | Use it for |
-| --- | --- | --- |
-| Initialization | `oliphaunt_init`, `OliphauntConfig` | Open a native direct backend for the prepared `pgdata` child of a managed root; initialization does not create it |
-| Versioning | `oliphaunt_version` | Report the Oliphaunt runtime package version |
-| Raw protocol | `oliphaunt_exec_protocol` | Send PostgreSQL frontend protocol bytes and receive backend messages |
-| Streaming | `oliphaunt_exec_protocol_raw_stream`, response sink callbacks | Handle large raw protocol responses without forcing one contiguous response buffer |
-| Simple SQL | `oliphaunt_exec_simple_query` | Execute one SQL string without constructing a frontend protocol frame |
-| Cancellation | `oliphaunt_cancel` | Request cancellation of the active PostgreSQL operation on a handle |
-| Response ownership | `OliphauntResponse`, `oliphaunt_free_response` | Free ABI-owned buffers exactly once |
-| Errors | `OliphauntErrorCapture`, the `_with_error` operation variants, `oliphaunt_copy_last_error` | Capture an asynchronous FFI operation's error before its native worker returns, or copy a synchronous caller's operation-local error into caller-owned memory |
-| Data movement | `oliphaunt_backup`, `oliphaunt_restore`, `OliphauntRestoreOptions` | Back up PostgreSQL data from an open managed root and restore it into a new or existing-empty receiving root |
-| Static extensions | `oliphaunt_register_static_extensions`, `OliphauntStaticExtension`, `OliphauntStaticExtensionSymbol` | Register process-wide statically linked extension modules before backend startup |
-| Lifecycle | `oliphaunt_detach`, `oliphaunt_logical_generation`, `oliphaunt_close_if_generation`, `oliphaunt_close` | Detach a logical lease, guard host cleanup against stale leases, or terminate the resident backend |
-
-Most app developers use a language SDK instead of calling the C ABI directly.
-The C ABI is primarily for binding authors and applications that need the native
-runtime boundary itself.
-
-**Unreleased checkout ABI v11:** `OliphauntConfig` appends the nullable
-`const char *icu_data_dir` field. Binding authors must use the matching v11
-header and ABI version; an older struct must not be passed as v11. Supply the
-selected canonical ICU data directory explicitly for an ICU database. The field
-is optional for configurations that do not select external ICU data. This is a
-checkout change, not a claim that ABI v11 has been publicly released.
-
-The optional embedded module directory remains at
-`OliphauntConfig.module_dir`. A non-empty path is copied into the handle and is
-authoritative over process environment and release-layout discovery. Set it to
-`NULL` for the sensible default: a valid `OLIPHAUNT_EMBEDDED_MODULE_DIR`, then
-packaged release-layout discovery.
-
-Hosts that schedule one FFI call on a worker thread and resume user code on a
-different thread use the matching `_with_error` entry point. They pass a
-required `OliphauntErrorCapture`; the operation fills it before releasing its
-native handle lease and returning. The fixed 1,028-byte layout contains a
-32-bit UTF-8 byte length from 0 through 1,023 followed by a 1,024-byte
-NUL-terminated message; capture does not further truncate the runtime's
-equally bounded error.
-Successful calls clear the entire capture. This keeps concurrent
-Promise failures attributable to their own native invocation instead of a
-later shared handle error.
-
-Bindings call `oliphaunt_copy_last_error` on the same thread immediately after
-a failed operation. The runtime keeps that operation's error in owned
-thread-local storage, so another thread's failed cancellation or database call
-cannot change the error between a size probe and the subsequent copy. Repeated
-copies remain stable until that thread begins another fallible C operation. If
-there is no operation-local snapshot, the function atomically reads the latest
-handle error, or the process-global error when passed `NULL`.
-
-The return value is the full UTF-8 byte length even when the supplied buffer is
-smaller, and nonempty output capacity is always NUL-terminated. The ABI exposes
-no borrowed error pointer; bindings keep the copied message in language-owned
-memory.
-
-A raw-stream callback rejection returns
-`OLIPHAUNT_STREAM_CALLBACK_ABORTED` only after the runtime has confirmed
-`ReadyForQuery`. Negative stream results identify native validation, transport,
-backend, or recovery failures and take precedence over a simultaneous binding
-callback exception.
-
-Direct-mode `oliphaunt_detach` leaves the same-PGDATA backend resident so a later
-init can acquire a new logical lease. Binding authors capture the nonzero
-`oliphaunt_logical_generation` immediately after every successful init and use
-`oliphaunt_close_if_generation` during host-environment teardown. It
-closes only the matching current lease; while a newer lease is active, a stale
-generation returns a positive no-op result and must not terminate that owner.
-Once terminal close has completed, cleanup returns zero because the terminal
-condition is already satisfied. Invalid arguments or lifecycle-state errors
-return a negative result. `oliphaunt_close` is the unconditional terminal
-operation for hosts that serialize the entire process lifetime themselves.
+Compile against the `oliphaunt.h` shipped with your native library. Use the header's `OLIPHAUNT_ABI_VERSION` macro rather than copying a numeric ABI version into application code.
+
+## Configuration and data types
+
+| Type | Contract |
+| --- | --- |
+| `OliphauntHandle` | Opaque native handle; do not inspect or free it directly |
+| `OliphauntConfig` | ABI version, prepared `pgdata`, resource paths, identity, flags, startup arguments |
+| `OliphauntResponse` | Owned `data` pointer and `len`; release with `oliphaunt_free_response` |
+| `OliphauntErrorCapture` | Caller-owned bounded message buffer and length |
+| `OliphauntRestoreStreamOptions` | Destination and read callback for streaming an archive |
+| `OliphauntRestoreOptions` | ABI version, managed-root destination, archive bytes and length |
+| `OliphauntStaticExtension` | Statically linked module descriptor |
+
+`pgdata` names the child of an existing managed root. `runtime_dir` selects runtime resources. `module_dir` names an existing PostgreSQL module directory or uses discovery when null. `username` and `database` select existing identities.
+
+`startup_args` contains `-c`, `name=value` pairs; storage-routing settings are rejected. Leave `flags` zero unless your binding already owns the required external root lock.
+
+## Open and execute
+
+| Function | Operation |
+| --- | --- |
+| `oliphaunt_init` | Open a direct logical lease |
+| `oliphaunt_exec_simple_query` | Send simple SQL and return protocol bytes |
+| `oliphaunt_exec_protocol` | Exchange buffered protocol bytes |
+| `oliphaunt_exec_protocol_raw_stream` | Deliver response chunks through a callback |
+| `oliphaunt_backup` | Create an owned native physical archive |
+| `oliphaunt_restore` | Restore into new or empty managed storage |
+| `oliphaunt_backup_stream_with_error` | Write an archive through a callback |
+| `oliphaunt_restore_stream_with_error` | Read an archive through a callback |
+| `oliphaunt_free_response` | Release response ownership |
+
+Async FFI hosts should use the corresponding `_with_error` functions for open, queries, streaming, backup, restore, and detach. These preserve return codes and response ownership while filling an error capture before returning.
+
+## Streaming
+
+`OliphauntStreamCallback` receives `(context, data, len)` and returns `int32_t`. Bytes are borrowed for the callback duration. Zero continues delivery; nonzero stops it and initiates protocol recovery. Ordinary same-handle operations are forbidden while streaming; cancellation is permitted.
+
+For incremental protocol input, capture `oliphaunt_protocol_stream_token(handle)` during an active stream and pass complete frontend frames to `oliphaunt_feed_protocol_stream`. A busy result accepts no bytes; retry after the backend consumes input. Stop feeding when the stream ends. The token is scoped to that stream, including across detach and reopen. See the header for frame and COPY sequencing rules.
+
+Archive read callbacks set `read_len` to zero at end of input. Archive read and write callbacks run synchronously and must not re-enter the database.
+
+## Lifecycle
+
+| Function | Operation |
+| --- | --- |
+| `oliphaunt_cancel` | Cross-thread interrupt request |
+| `oliphaunt_detach` | End a logical lease while retaining the resident backend |
+| `oliphaunt_logical_generation` | Read the current nonzero lease generation, or zero when unavailable |
+| `oliphaunt_close_if_generation` | Terminal close guarded by generation ownership |
+| `oliphaunt_close` | Unconditional process-terminal close of the resident handle |
+
+Guarded close returns zero for completed/already completed close, one for a stale active generation that does nothing, and minus one for invalid zero generation or an internal failure. Serialize other operations according to the header contract.
+
+## Errors and version
+
+`oliphaunt_copy_last_error(handle, out, capacity)` returns the full UTF-8 length excluding the NUL terminator. With nonzero capacity, `out` must be nonnull and the copied result is NUL-terminated. Copy immediately on the failing operation's thread, or use an operation-owned error capture.
+
+`oliphaunt_version()` returns the runtime version. `oliphaunt_register_static_extensions` registers descriptors before backend startup.
+
+Read [Build a binding](/docs/sdk/c-abi/guide) for ownership and recovery requirements before wrapping these functions.
diff --git a/src/docs/content/sdk/c-abi/guide.mdx b/src/docs/content/sdk/c-abi/guide.mdx
index 876c57095..027a0ea5b 100644
--- a/src/docs/content/sdk/c-abi/guide.mdx
+++ b/src/docs/content/sdk/c-abi/guide.mdx
@@ -1,144 +1,70 @@
---
-title: Build A Binding
-description: Build a language binding over opaque C handles, raw protocol bytes, explicit response ownership, lifecycle, extensions, and backup APIs.
+title: Build a binding
+description: Prepare storage and manage scheduling, errors, buffers, streaming, and native lifecycle.
---
-# Build A Binding
+A binding translates its language's database API into the C ABI and owns the scheduling around that boundary. Begin with the [C example](/docs/sdk/c-abi).
-Use the C ABI when building language bindings or platform SDKs. App developers
-usually choose a native SDK, Rust WASIX, or WASIX TypeScript instead.
+## Prepare a managed root
-
-Use this surface when you need opaque handles, explicit response ownership, and
-the native runtime boundary. App-facing SDKs own typed queries and platform
-lifecycle integration.
-
+Create persistent storage with a native SDK before calling `oliphaunt_init`. For example, run this separate Rust program using the [Rust SDK](/docs/sdk/rust):
-
+```rust
+use oliphaunt::{DatabaseStorage, Oliphaunt};
-
-
-
-### Install
-
-Consume the released headers, libraries, and runtime assets for your target.
-Language bindings package those artifacts through the target ecosystem so app
-developers install one SDK surface.
-
-
-
-
-### Open and query
-
-Prepare a managed root, open its `pgdata` directory, send raw protocol bytes,
-read backend messages, and close the handle. The C runtime validates an exact
-`.oliphaunt.json`, PostgreSQL 18 `PG_VERSION`, a real `global` directory with
-nonempty `pg_control`, and a real `pg_wal`; it does not initialize an empty root.
+fn main() -> oliphaunt::Result<()> {
+ let mut db = Oliphaunt::builder()
+ .storage(DatabaseStorage::Directory("./data/example".into()))
+ .direct()
+ .open()?;
+ db.close()
+}
+```
-```c
-#include
-#include
+After that process exits, pass `./data/example/pgdata` to the C example. The surrounding root also contains `.oliphaunt.json`; retain it. Pointing the ABI at an ordinary empty directory or an arbitrary `initdb` directory does not establish the managed-root contract.
-OliphauntConfig config = {
- .abi_version = OLIPHAUNT_ABI_VERSION,
- .pgdata = "/app/data/main.oliphaunt/pgdata",
- .username = "app",
- .database = "app",
-};
+## Serialize database operations
-OliphauntHandle *db = NULL;
-int rc = oliphaunt_init(&config, &db);
-if (rc != 0) {
- return rc;
-}
-
-OliphauntResponse response = {0};
-const char *sql = "SELECT 1::text AS value";
-rc = oliphaunt_exec_simple_query(db, sql, strlen(sql), &response);
-oliphaunt_free_response(&response);
-oliphaunt_close(db);
-```
+One direct backend resides in the process. Serialize ordinary calls on the handle, including queries, backups, detach, and close. Use an owner thread or queue if your language's callers are concurrent. `oliphaunt_cancel` can interrupt an active operation from another thread. Token-bound stream input may also come from another thread; follow the [streaming contract](/docs/sdk/c-abi/api-reference#streaming).
-Higher-level SDKs own SQL builders, typed parsing, async scheduling, resource
-selection, and lifecycle integration.
+Do not run PostgreSQL work on a UI thread. Keep request buffers and configuration strings alive for the duration of their native call. The high-level SDKs provide broker/server modes when process isolation or multiple sessions are needed.
-
-
+## Own response buffers
-### Configure
+Zero-initialize `OliphauntResponse`. After a buffered query or backup, consume or copy its bytes, then call `oliphaunt_free_response` exactly once. Do not free the data with your language's allocator or read it after release.
-`OliphauntConfig` contains the PGDATA path, optional runtime and module
-directories, username, database, and PostgreSQL startup arguments.
-The unreleased v11 header also appends nullable `icu_data_dir` for explicitly
-selected ICU data. Use the matching header and ABI version together; do not
-reuse an older binary struct with the new version number.
-Set `flags` to zero for normal ownership, or to
-`OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK` when the host already owns the managed
-root lock for the lifetime of the handle. A detached resident runtime accepts a
-new logical lease only when the reopen uses the same lock-ownership mode. Other
-flag bits are rejected.
-Higher-level SDKs prepare storage and translate direct-runtime settings into
-this record.
+Decode PostgreSQL fields and error messages before releasing the response. Use protocol parameter binding for untrusted values; the simple-query helper accepts SQL text and does not interpolate values safely for you.
-
-
+## Capture errors before switching threads
-### Choose a mode
+Use the `_with_error` variants for async FFI schedulers. They write an `OliphauntErrorCapture` into caller-owned memory before the native operation returns. The capture remains available after your language resumes on another thread.
-The C ABI is the native-direct boundary and owns one serialized embedded
-session. Choose broker or server through a language SDK when process isolation
-or independent client sessions are required.
+For synchronous callers, `oliphaunt_copy_last_error` can copy the failing operation's error on the same thread. Read it before beginning another fallible operation. Do not retain a borrowed pointer to shared error storage.
-
-
+## Stream protocol responses
-### Handle lifecycle
+`oliphaunt_exec_protocol_raw_stream` calls your callback with borrowed bytes valid only for that invocation. Copy them if the receiving language needs them later.
-Each binding runs calls through a single owner queue or equivalent serial
-executor. A host with exactly one serialized lifetime owner can terminate the
-resident runtime with `oliphaunt_close`. A binding with independent environment,
-worker, or finalizer cleanup owners must instead capture
-`oliphaunt_logical_generation(db)` immediately after a successful init and pass
-only that token to `oliphaunt_close_if_generation` during teardown. A stale
-owner receives a positive non-error result while a newer logical lease remains
-active, instead of closing that lease. If terminal close already completed, the
-same cleanup is satisfied with zero. Close rejects queued work and waits for
-active work according to the SDK's platform contract.
+Return zero to continue. Returning nonzero stops further callback delivery and asks the runtime to recover the protocol boundary. `OLIPHAUNT_STREAM_CALLBACK_ABORTED` indicates the callback-stop outcome; a negative result signals a validation, transport, backend, or recovery failure.
-
-
+Do not query, back up, detach, close, or start another stream from the callback. Out-of-band cancellation and input for the active stream token are allowed. Reuse the database only when recovery is confirmed.
-### Select extensions
+## Back up and restore
-Place dynamic extension files under the configured runtime/module directories,
-or call `oliphaunt_register_static_extensions` before `oliphaunt_init` for
-statically linked modules. The application still enables an installed
-extension with PostgreSQL SQL such as `CREATE EXTENSION`.
+`oliphaunt_backup` returns the native physical archive through an owned response buffer. Copy or save the archive before freeing the response.
-
-
+Pass `OliphauntRestoreOptions` to `oliphaunt_restore`. Its `destination` names a new or empty managed root, not its `pgdata` child. Supply the ABI version and archive bytes. Restore rejects a nonempty destination.
-### Back up and restore
+If backup reports that exiting backup mode is unconfirmed, do not run another query. Close or detach the handle and restart the process before reopening PostgreSQL.
-Use `oliphaunt_backup` and `oliphaunt_restore` for the one native PostgreSQL 18
-physical archive. Restore accepts a new or existing-empty managed-root
-destination and does not replace nonempty data.
+## Register extensions
-
-
+Link the required native extension code and runtime resources. For static linking, call `oliphaunt_register_static_extensions` before init with the matching descriptors. The registry becomes immutable once startup begins. Enable database-local extension objects through SQL after open.
-
+## End ownership safely
-## Troubleshooting
+`oliphaunt_detach` ends the logical lease while retaining the resident backend. `oliphaunt_close` is terminal for that backend's process lifetime; after success, never dereference the handle again.
-Inspect return codes and call `oliphaunt_copy_last_error` on that same thread
-immediately after a failure. Its operation-local snapshot is stable across the
-usual size-probe and copy calls even when another thread is cancelling or
-running work on the handle. Then check missing runtime resources, PGDATA locks,
-and PostgreSQL errors. Language bindings may parse protocol errors into richer
-ecosystem-native types.
+When independent host environments or finalizers can own cleanup, capture the nonzero value from `oliphaunt_logical_generation` immediately after init. Retain that token for cleanup and call `oliphaunt_close_if_generation`. A stale generation cannot close a newer lease.
-If the host's FFI scheduler resumes on a different thread, call the matching
-`_with_error` operation and keep one `OliphauntErrorCapture` with that call.
-Reading `oliphaunt_copy_last_error` later on the resumed thread cannot recover
-worker-local attribution. A null capture is rejected before the operation runs.
+Keep explicit close as the observable cleanup path. A finalizer can provide a fallback, but it cannot replace reporting teardown errors to the caller.
diff --git a/src/docs/content/sdk/c-abi/index.mdx b/src/docs/content/sdk/c-abi/index.mdx
index cb1305520..a0881002c 100644
--- a/src/docs/content/sdk/c-abi/index.mdx
+++ b/src/docs/content/sdk/c-abi/index.mdx
@@ -1,89 +1,61 @@
---
title: C ABI
-description: Native runtime boundary for language bindings and direct C consumers.
+description: Use liboliphaunt from C, C++, or a custom language binding.
---
-
+Use `liboliphaunt` when you need a C boundary for native PostgreSQL. Application developers can usually start faster with a [language SDK](/docs/sdk).
-`liboliphaunt` is the native runtime boundary for SDKs and direct C consumers.
-Most app developers use a platform SDK, but binding authors use the C ABI as the
-stable layer under Swift, Kotlin, React Native, TypeScript native adapters, and
-other language bindings.
+The ABI returns PostgreSQL protocol bytes and owns native response buffers. Your binding supplies typed decoding, scheduling, and application-level lifecycle.
-Use this surface when you are writing a new SDK, integrating from a C or C++
-application, or validating the native runtime independently from a language
-wrapper.
+## Install and prepare storage
-## Install
+Download the native library, `oliphaunt.h`, and runtime resources for your platform from the [native runtime release](https://github.com/f0rr0/oliphaunt/releases/tag/liboliphaunt-native-v{{release:liboliphaunt-native}}). Compile against the matching header and link the matching library. Preserve the release's runtime-resource layout.
-Consume the released headers, libraries, and runtime assets for the target you
-are binding. Language SDKs package those artifacts through their own ecosystems,
-so app developers usually install the Rust, Swift, Kotlin, React Native,
-TypeScript, Rust WASIX, or WASIX TypeScript SDK.
+`oliphaunt_init` opens the `pgdata` child of an **already-prepared managed root**. It does not initialize an empty directory. Prepare the root through a native SDK, close its owner, and then use the root from your C program. See [Prepare a managed root](/docs/sdk/c-abi/guide#prepare-a-managed-root).
-The public boundary is intentionally small:
+## Open and query
-- open a native direct session over an already-prepared managed root;
-- execute raw PostgreSQL protocol bytes or simple SQL;
-- stream large protocol responses;
-- back up or restore the native physical archive;
-- read error strings;
-- close or detach according to the process lifecycle.
+Save this as `example.c`. Its argument is the `pgdata` path inside your prepared root. `runtime_dir` and `module_dir` use release-layout discovery unless you set explicit paths.
-The ABI owns handles and response buffers. Language bindings own serialization,
-typed query helpers, task scheduling, and platform packaging.
-
-## Open And Query
-
-The C ABI uses opaque handles and explicit response ownership:
+
```c
#include
+#include
#include
-OliphauntHandle *handle = NULL;
-OliphauntConfig config = {
- .abi_version = OLIPHAUNT_ABI_VERSION,
- .pgdata = "./app-data/main.oliphaunt/pgdata",
- .username = "app",
- .database = "app",
-};
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s /path/to/root/pgdata\n", argv[0]);
+ return 2;
+ }
+ OliphauntHandle *handle = NULL;
+ OliphauntErrorCapture error = {0};
+ OliphauntConfig config = {
+ .abi_version = OLIPHAUNT_ABI_VERSION,
+ .pgdata = argv[1],
+ .username = "postgres",
+ .database = "postgres",
+ };
+ if (oliphaunt_init_with_error(&config, &handle, &error) != 0) {
+ fprintf(stderr, "%s\n", error.message);
+ return 1;
+ }
-int32_t status = oliphaunt_init(&config, &handle);
-if (status == 0) {
OliphauntResponse response = {0};
- const char *sql = "SELECT 1::text AS value";
- status = oliphaunt_exec_simple_query(handle, sql, strlen(sql), &response);
+ const char *sql = "SELECT 42::int4 AS answer";
+ int32_t status = oliphaunt_exec_simple_query_with_error(
+ handle, sql, strlen(sql), &response, &error);
+ if (status != 0) fprintf(stderr, "%s\n", error.message);
+ else printf("Received %zu PostgreSQL protocol bytes\n", response.len);
oliphaunt_free_response(&response);
+ int32_t closed = oliphaunt_close(handle);
+ return status != 0 || closed != 0;
}
-oliphaunt_close(handle);
```
-## Runtime Shape
-
-The C ABI is the native direct runtime boundary. Its fixed ABI defines protocol,
-streaming, backup/restore, extension, cancellation, and lifecycle support.
-
-Direct mode owns one serialized embedded PostgreSQL session. Language SDK APIs
-provide the higher-level broker and server modes.
-
-## App Responsibilities
-
-Bindings and direct C consumers own the app-facing contract above the ABI:
-
-- Keep all cross-language query transport on raw PostgreSQL protocol bytes or
- simple SQL helpers provided by the ABI.
-- Serialize work according to the selected runtime mode.
-- Select exact SQL extension names before opening the database.
-- Translate error strings into ecosystem-native types.
-- Use ABI backup and restore calls instead of copying live PGDATA.
-- Capture the logical generation immediately after init when more than one host
- environment or finalizer can own cleanup, and use generation-guarded terminal
- close so stale teardown cannot close a newer lease.
+The response is binary protocol data, not a string or a decoded row. Parse backend messages to read the result and detect PostgreSQL `ErrorResponse` messages. A successful transport call is not a substitute for inspecting the SQL result.
-## First Query
+## Next steps
-Use [Build a Binding](/docs/sdk/c-abi/guide) for open, query, close,
-lifecycle, extension, and backup behavior. Use the
-[API reference](/docs/sdk/c-abi/api-reference) for the public handle and
-function map.
+Read [Build a binding](/docs/sdk/c-abi/guide) for scheduling, buffer ownership, and lifecycle. Use the [API reference](/docs/sdk/c-abi/api-reference) for configuration and function groups.
diff --git a/src/docs/content/sdk/index.mdx b/src/docs/content/sdk/index.mdx
index d53686a01..291b368b7 100644
--- a/src/docs/content/sdk/index.mdx
+++ b/src/docs/content/sdk/index.mdx
@@ -1,72 +1,16 @@
---
title: SDKs
-description: Choose a native SDK, Rust WASIX, WASIX TypeScript, or the C ABI by runtime owner and application target.
+description: Choose the Oliphaunt package for your language and application runtime.
---
-# SDKs
-
-Choose the SDK that owns the database runtime in the deployed application.
-Oliphaunt products share PostgreSQL concepts and versioned carriers, but each SDK
-keeps ecosystem-native naming and exposes only the behavior its host supports.
+Choose an SDK by where your application runs. Every quickstart shows how to install its package, run a query, and close the database.
-## How To Choose
-
-- Choose Rust, Swift, Kotlin, React Native, or TypeScript when the app
- embeds or supervises the native runtime family.
-- Choose Rust WASIX (`oliphaunt-wasix`) when Rust owns the portable WASIX host
- and needs Rust direct, local server, extension, or data-movement APIs.
-- Choose WASIX TypeScript (`@oliphaunt/wasix-ts`) for a caller-realm browser
- database or the native Node.js, Bun, Deno, and Electron placements: the
- default Rust owner, explicit `/direct`, or a JavaScript `/worker` realm.
- Memory is the default; extensions are selective imports, IndexedDB and OPFS
- persistence are browser opt-ins, and directory persistence is a native-host opt-in.
-- Choose the C ABI only when building another native language binding or
- integrating `liboliphaunt` directly.
-
-Native TypeScript and WASIX TypeScript are separate packages. Neither selects
-or falls back to the other. Rust WASIX and WASIX TypeScript can
-share portable runtime and extension carriers without sharing a public API.
-
-## Shared Concepts, Separate APIs
-
-The products use a cohesive vocabulary where the host actually supports it:
-
-- storage describes database lifetime and persistence;
-- exact extension selection keeps browser payloads narrow and native activation explicit;
-- structured PostgreSQL errors preserve SQLSTATE where available; and
-- explicit lifecycle methods define when runtime or persistent state is
- released.
-
-Those concepts are not a signature-parity promise. Native SDKs expose their
-engine modes. Rust WASIX adds Rust host, server, physical archive, and optional
-tool APIs. WASIX TypeScript exposes `open`, typed and raw query operations,
-callback transactions, physical `backup`, static `restore`, and `close`; its
-optional tools package adds `pgDump` for root, direct, or Worker handles and
-`psql` for all three native placements or a browser Worker handle, while explicit server
-subpaths add a local endpoint on Node, Bun, Deno, and Electron.
-
-
-
-## What Each SDK Page Answers
+## Native or WASIX?
-| Question | Why it matters |
-| --- | --- |
-| Which package do I install? | Package identity determines native versus WASIX runtime ownership. |
-| Which host runs PostgreSQL? | Native process, Rust WASIX host, browser realm, Rust owner, direct realm, and Worker placements have different lifecycle behavior. |
-| What is the storage default? | Sensible defaults avoid configuration while explicit storage opts into persistence. |
-| How do I select extensions? | Native SDKs select exact SQL names; WASIX TypeScript imports exact portable descriptors. |
-| Which APIs are actually present? | Server, tools, transaction-helper, and data-movement support differs by product. |
+Native SDKs run the native PostgreSQL runtime. Use them for mobile apps and desktop applications that can ship native libraries. Use broker mode to isolate database execution. Rust and desktop TypeScript also provide a local PostgreSQL server for drivers and ORMs.
-## Where To Go Next
+WASIX SDKs run PostgreSQL compiled to WebAssembly. Use WASIX TypeScript in browsers, or either WASIX binding when you want that runtime in a desktop host. Select WASIX explicitly; the native packages do not switch to it automatically.
-- Use [Start](/docs/start) for the shortest first-query path.
-- Use [Runtime Support](/docs/reference/capabilities) before relying on a
- mode or feature in a packaged app.
-- Use [WASIX TypeScript](/docs/sdk/wasix-typescript) for browser direct or
- server actor, direct, and Worker execution, error recovery,
- host-specific persistent storage, and selective extensions.
-- Use [Rust WASIX](/docs/sdk/wasix-rust) for the Rust portable host.
-- Use [Native Runtime](/docs/learn/native-runtime) for native direct, broker,
- and server semantics.
+See [SDKs and platforms](/docs/reference/sdk-products) for package names and [runtime support](/docs/reference/capabilities) for storage, tools, and concurrency differences.
diff --git a/src/docs/content/sdk/kotlin/api-reference.md b/src/docs/content/sdk/kotlin/api-reference.md
index e9b93c246..35cf4cddb 100644
--- a/src/docs/content/sdk/kotlin/api-reference.md
+++ b/src/docs/content/sdk/kotlin/api-reference.md
@@ -1,59 +1,53 @@
---
-title: API Reference
-description: Kotlin and Android SDK API map for configuration, coroutine execution, lifecycle, and resources.
+title: Kotlin API reference
+description: Android configuration, coroutine operations, typed results, and exceptions.
---
-# API Reference
-
-This page maps the Kotlin SDK
-surface by task.
-
-| Area | Public surface | Use it for |
-| --- | --- | --- |
-| Opening | `Oliphaunt.open`, `OliphauntConfig`, `DatabaseStorage` | Use temporary storage by default or an explicit persistent directory |
-| Android facade | `Oliphaunt` | Resolve Android resources, ABI assets, and app-context defaults |
-| Single-statement SQL | `query`, `execute`, `QueryResult` | Return ordered raw rows or assert that one extended-query command returns no rows |
-| Multi-statement and metadata | `exec`, `describe` | Return ordered command-or-row results or resolve parameter/result OIDs without executing |
-| Parameters and rows | `PostgresOid`, `QueryParam`, `ValueFormat`, `QueryRow.value`, `PostgresDecoder`, `PostgresDecoders` | Encode typed/null values and decode by OID-validated index or unambiguous name while retaining `ByteArray` |
-| Raw protocol | database `execProtocolRaw`, `execProtocolRawStream` | Send PostgreSQL protocol bytes as one result or synchronous callback chunks; raw ownership stays outside managed transaction handles, all same-handle work is rejected while a callback runs, confirmed callback recovery leaves the session reusable, and transport/recovery failures poison it |
-| Transactions | `transaction`, transaction `query`/`execute`/`exec`/`describe`, `OliphauntTransaction.rollback`, transaction `isClosed` | Keep typed work inside the pinned session, return to commit, explicitly roll back without a later commit, and use savepoints for nested work |
-| Lifecycle | database `isClosed`, `cancel`, `close` | FIFO admission drains calls accepted before the close cutoff; cancellation remains available until native teardown starts, with nonblocking cleaner fallback for forgotten handles |
-| Data movement | `backup`, static `restore` | Move app data through the native physical archive |
-| Diagnostics | result `notices`, `OliphauntException`, `PostgresException`, `OliphauntTransactionRollbackException`, `OliphauntTransactionDatabaseException` | Preserve PostgreSQL diagnostics and independent transaction failures without dropping the callback exception |
-
-```kotlin
-val result = database.query(
- "SELECT $1::int4 AS answer",
- listOf(QueryParam.int(41)),
-)
-val answer = result.rows.first().value("answer", PostgresDecoders.int)
-```
-
-The cross-SDK behavior follows the
-[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md).
-
-Managed transaction callbacks must not issue outer-lifecycle SQL: `BEGIN`/`START
-TRANSACTION`, `COMMIT`/`END`, a full `ROLLBACK`/`ABORT` (with or without `AND
-[NO] CHAIN`), or `PREPARE TRANSACTION`. Use
-`rollback()` or return from the callback for outer settlement; `SAVEPOINT`,
-`RELEASE SAVEPOINT`, and `ROLLBACK TO SAVEPOINT` remain supported SQL. PostgreSQL
-reports `ROLLBACK TO` and `ROLLBACK AND CHAIN` with the same `ROLLBACK` command
-tag and transactional ready status, so the SDK rejects `ROLLBACK`/`ABORT ...
-AND CHAIN` before dispatch and still validates every actual protocol boundary.
-If the callback catches a poisoning database or rollback error and returns, the
-transaction still fails with the stored original exception.
-
-After automatic rollback succeeds, the original callback exception is rethrown.
-`OliphauntTransactionRollbackException` exposes `callbackError` and
-`rollbackError`, uses the callback as `cause`, and records the rollback as a
-suppressed exception. If the callback throws a different exception after an
-earlier independent database or protocol failure poisoned or expired ownership,
-`OliphauntTransactionDatabaseException` exposes `callbackError` and
-`databaseError`, uses the callback as `cause`, and records the database error as
-a suppressed exception; the database is close-only. Ordinary PostgreSQL
-statement errors that remain safely rollbackable do not automatically create
-either composite exception.
-
-Android apps use the Android facade for packaged runtime resources. It keeps
-native library loading, selected extension assets, and app-private storage in
-the platform layer.
+Import `dev.oliphaunt.*`. The Android `Oliphaunt` facade prepares runtime resources and returns an `OliphauntDatabase`.
+
+## Open and restore
+
+| Function | Result |
+| --- | --- |
+| `Oliphaunt.open(context, config, runtimeDirectory, resourceRoot)` | Suspends and returns `OliphauntDatabase` |
+| `Oliphaunt.restore(context, destination, bytes)` | Restores into a new or empty `File` destination |
+
+Only `context` is required for `open`. Resource overrides are optional `File` values; normal applications use package defaults.
+
+| `OliphauntConfig` field | Type / default |
+| --- | --- |
+| `storage` | `DatabaseStorage.TemporaryDirectory` |
+| Persistent storage | `DatabaseStorage.Directory(File)` or `DatabaseStorage.ApplicationData(name)` |
+| `startupGucs` | `List`; empty |
+| `username`, `database` | Nullable strings; fresh roots use `postgres` |
+| `extensions` | `List`; empty |
+
+The spelling is `startupGucs` in Kotlin. `PostgresStartupGuc` carries a setting name and value.
+
+## Broker mode
+
+`OliphauntBroker.open(context, config, options)` returns the same database interface from a separate process. Use application-data names for persistent broker storage. See [mobile broker setup](/docs/learn/mobile-stability#broker-mode) for platform requirements, file-based restore, deadlines, and failure handling.
+
+## Query extensions
+
+`query`, `execute`, `exec`, and `describe` are public extension functions on database and transaction handles. Import them explicitly or use the package import above.
+
+`query(sql, parameters)` returns `QueryResult`; `execute` returns `CommandResult`. `exec` returns ordered results for multiple statements, and `describe` returns statement metadata. Parameters are `List` values such as `QueryParam.int(...)` and `QueryParam.text(...)`.
+
+Read `result.rows` and decode with `row.value(column, decoder)`, using a name or index and a `PostgresDecoders` member. Raw bytes are available through `raw`, text through `text`, and null values remain nullable. Duplicate column names require positional lookup.
+
+## Transactions and lifecycle
+
+`transaction { tx -> ... }` returns the callback result after commit. Throwing rolls back. The callback receives typed query methods and `rollback()`; the handle expires after settlement. Savepoints are allowed, but manual outer transaction-lifecycle SQL is unsupported.
+
+`backup()` returns `ByteArray`. `cancel()` interrupts active work. `close()` performs observable teardown and `isClosed` reports terminal state. All are suspend functions except the state property. Coroutine cancellation alone is not the PostgreSQL interrupt API.
+
+## Raw protocol
+
+`execProtocolRaw(request)` returns a buffered `ByteArray`. `execProtocolRawStream` delivers raw chunks through a synchronous callback. Do not re-enter ordinary database or transaction methods from that callback. These methods belong to the database, not callback transactions.
+
+## Exceptions
+
+`PostgresException` contains `postgresError`, including nullable `sqlstate`. `OliphauntException` represents SDK failures. Composite transaction exceptions preserve `callbackError` plus `rollbackError` or `databaseError`. An unrecoverable protocol or teardown failure makes the database terminal; close it and reopen persistent storage when appropriate.
+
+See the [Kotlin guide](/docs/sdk/kotlin/guide) for recipes and troubleshooting.
diff --git a/src/docs/content/sdk/kotlin/guide.mdx b/src/docs/content/sdk/kotlin/guide.mdx
index 42faba483..9fd073577 100644
--- a/src/docs/content/sdk/kotlin/guide.mdx
+++ b/src/docs/content/sdk/kotlin/guide.mdx
@@ -1,222 +1,107 @@
---
-title: Build With Kotlin
-description: Add Oliphaunt to an Android app with Gradle, coroutines, app-private storage, selected extensions, backup, and app-owned lifecycle actions.
+title: Kotlin guide
+description: Use typed queries, transactions, extensions, and backups in Android apps.
---
-# Build With Kotlin
+These recipes run in a coroutine with an open `db` from the [Kotlin quickstart](/docs/sdk/kotlin). Import `dev.oliphaunt.*` for the database types and query extension functions.
-Use the Kotlin SDK in Android apps. It provides coroutine-friendly APIs over the
-native runtime and owns Android resource hydration, storage validation, and
-extension materialization.
+## Query application data
-
-React Native on Android delegates runtime behavior through this SDK. Native
-Android apps use the Kotlin facade directly for resource hydration and ABI
-selection.
-
-
-
-
-
-
+```kotlin
+db.execute("CREATE TABLE IF NOT EXISTS notes (id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, body text NOT NULL)")
+val inserted = db.query(
+ "INSERT INTO notes (body) VALUES ($1) RETURNING id",
+ parameters = listOf(QueryParam.text("First note")),
+)
+val id = inserted.rows[0].value("id", PostgresDecoders.long)
+```
-### Install
+Bind values using `QueryParam` helpers and choose a decoder matching the PostgreSQL column type. SQL null returns `null`; decode by column index when a result has duplicate column names.
-Add the Android SDK and app-applied Gradle plugin. The plugin resolves and
-packages native runtime artifacts, Android ABIs, and exact extension files.
+## Run a transaction
```kotlin
-plugins {
- id("com.android.application")
- id("dev.oliphaunt.android") version "{{release:oliphaunt-kotlin}}"
-}
-
-dependencies {
- implementation("dev.oliphaunt:oliphaunt-android:{{release:oliphaunt-kotlin}}")
-}
-
-oliphaunt {
- selectedExtensions.add("vector")
+db.transaction { tx ->
+ tx.execute(
+ "INSERT INTO notes (body) VALUES ($1)",
+ parameters = listOf(QueryParam.text("First")),
+ )
+ tx.execute(
+ "INSERT INTO notes (body) VALUES ($1)",
+ parameters = listOf(QueryParam.text("Second")),
+ )
}
```
-Storage defaults to an SDK-owned temporary directory. Choose an app-private
-directory when data must persist.
-
-
-
+Returning commits; throwing rolls back. Use `tx` for all callback statements. Do not call the outer `db` or send manual `BEGIN`, `COMMIT`, or full `ROLLBACK` SQL. Use `tx.rollback()` for explicit rollback. Savepoints are supported.
-### Open and query
+## Select extensions
-Create an `OliphauntConfig`, open a database, run SQL, and close it from
-coroutines.
+Choose extensions in the app's Gradle configuration:
```kotlin
-val database =
- Oliphaunt.open(
- context = context,
- config = OliphauntConfig(
- storage = DatabaseStorage.Directory(
- context.filesDir.resolve("main.oliphaunt").absolutePath,
- ),
- extensions = listOf(OliphauntExtension.VECTOR),
- ),
- )
-
-val rows = database.query("SELECT 1::text AS value")
-val value = rows.rows.first().value("value", PostgresDecoders.string)
-
-database.close()
+oliphaunt {
+ selectedExtensions.add("vector")
+}
```
-Share the opened database object through your app's dependency graph. It
-represents one serialized native session.
-
-
-
-
-### Create app data
-
-Use coroutine-friendly SQL helpers from repositories or use cases. Keep
-database ownership in an Android service object rather than inside a composable:
+Rebuild the app, then select its typed value when opening:
```kotlin
-database.execute(
- """
- CREATE TABLE IF NOT EXISTS notes (
- id bigserial PRIMARY KEY,
- title text NOT NULL,
- body text NOT NULL,
- created_at timestamptz NOT NULL DEFAULT now()
- )
- """.trimIndent(),
-)
-
-database.query(
- "INSERT INTO notes (title, body) VALUES ($1, $2) RETURNING id::text AS id",
- listOf(
- QueryParam.string("First note"),
- QueryParam.string("Stored by embedded PostgreSQL"),
+val db = Oliphaunt.open(
+ context,
+ OliphauntConfig(
+ storage = DatabaseStorage.Directory(context.filesDir.resolve("main.oliphaunt")),
+ extensions = listOf(OliphauntExtension.VECTOR),
),
)
-
-val notes =
- database.query("SELECT id, title FROM notes ORDER BY id DESC LIMIT 20")
-val firstTitle = notes.rows.first().value("title", PostgresDecoders.string)
+db.execute("CREATE EXTENSION IF NOT EXISTS vector")
```
-Expose app-specific suspend functions to UI code. The SDK owns the serialized
-native session underneath those calls.
-
-
-
-
-### Configure
-
-Configure storage, selected exact extensions, startup identity, and PostgreSQL
-startup GUCs through `OliphauntConfig` and the Android facade. Normal apps use
-packaged runtime assets; explicit asset locations remain advanced overrides.
-
-
-
-
-### Choose a mode
-
-Android direct mode owns one resident backend per app process and one physical
-session.
-
-
-
-
-### Handle lifecycle
-
-Database calls are suspending at the public boundary. A single-thread owner
-dispatcher runs storage preparation, JNI open, SQL/protocol work, backup, and
-close away from the Android UI thread. Ordinary work, transaction controls, and
-close share FIFO admission. A transaction or close is an atomic cutoff: calls
-admitted earlier drain before it, and incompatible later calls fail. `cancel()`
-uses a separate control dispatcher, and close completes its ownership transition
-even when its calling coroutine is cancelled. Cancellation remains available
-while close drains earlier admissions and stops when native teardown starts.
-Raw-stream callbacks are synchronous backpressure boundaries: while one is
-running, all same-handle database and transaction work is rejected, including
-work launched onto another coroutine dispatcher, except for out-of-band
-`cancel()`. A callback failure is returned only after confirmed
-protocol recovery and leaves the session reusable. A raw buffered or streaming
-transport/recovery failure poisons the database. Use `cancel()` and `close()`
-explicitly according to the app's lifecycle policy. A phantom-reference cleaner
-only schedules best-effort forgotten-handle cleanup on the owner; it does not
-replace explicit close or block the garbage collector thread. Run
-`execute("CHECKPOINT")` only when an explicit PostgreSQL checkpoint is needed.
-
-Inside `transaction {}`, use the transaction's typed `query`, `execute`, `exec`,
-and `describe` methods. Return to commit or call `rollback()` to settle the outer
-transaction; do not issue outer-lifecycle SQL such as `BEGIN`/`START TRANSACTION`,
-`COMMIT`/`END`, a full `ROLLBACK`/`ABORT` (with or without `AND [NO] CHAIN`), or
-`PREPARE TRANSACTION`. Nested `SAVEPOINT`, `RELEASE
-SAVEPOINT`, and `ROLLBACK TO SAVEPOINT` SQL is supported. PostgreSQL exposes
-`ROLLBACK TO` and `ROLLBACK AND CHAIN` with the same `ROLLBACK` command tag and
-transactional ready status, so the SDK rejects `ROLLBACK`/`ABORT ... AND CHAIN`
-before dispatch and still validates every actual protocol boundary. Raw
-protocol APIs stay on the database for callers that explicitly own transaction
-lifecycle.
+The Gradle plugin packages selected native artifacts and required dependencies. Check the [extension catalog](/docs/reference/extension-catalog) for available names.
-After automatic rollback succeeds, Kotlin rethrows the original callback
-exception. If the callback catches a poisoning database or rollback error and
-returns, the transaction still fails with that stored original exception. If
-rollback also fails,
-`OliphauntTransactionRollbackException.callbackError` and `.rollbackError`
-preserve both; the callback is the cause and rollback is suppressed. If the
-callback throws a different exception after an earlier independent database or
-protocol failure poisoned or expired transaction ownership,
-`OliphauntTransactionDatabaseException.callbackError` and `.databaseError`
-preserve both; the callback is the cause, the database error is suppressed, and
-the database is close-only. An ordinary PostgreSQL statement error that remains
-safely rollbackable is not automatically wrapped in either composite exception.
+## Choose process isolation
-
-
+The quickstart uses direct mode. For a separate database process, follow [mobile broker setup](/docs/learn/mobile-stability#broker-mode). Broker mode requires its own storage and restore path; use the recipes below for direct mode.
-### Select extensions
+## Back up and restore
-Select exact SQL extension names before opening the database. Android artifacts
-contain only those selected extensions and mandatory dependencies.
+Direct mode stays bound to one database root and configuration for the lifetime of the application process. Closing a handle does not let that process switch to another root. Prepare the restored data, then use it on the next launch.
-
-
-
-### Back up and restore
-
-Use `backup()` and static `restore(destination, bytes)` with Android
-file/document APIs. Restore accepts a new or existing-empty destination and
-rejects nonempty data without mutation.
+```kotlin
+val archive: ByteArray = db.backup()
+db.close()
+val destination = context.filesDir.resolve("restored.oliphaunt")
+Oliphaunt.restore(context, destination, archive)
+```
-
-
+On a subsequent application launch, open the restored destination:
-
+```kotlin
+val destination = context.filesDir.resolve("restored.oliphaunt")
+val restored = Oliphaunt.open(
+ context,
+ OliphauntConfig(storage = DatabaseStorage.Directory(destination)),
+)
+restored.close()
+```
-## Troubleshooting
+Restore requires a new or empty destination. Backups contain database state; the receiving app must also ship and select any required extensions. Use compatible native runtimes for physical restore.
-Check app storage permissions, storage ownership, missing native libraries, missing
-runtime resources, runtime errors, selected-extension artifacts, and
-SQLSTATE-bearing PostgreSQL errors.
+## Cancel and close
-## Development resource packaging
+Coroutine cancellation does not replace the SDK's database interrupt. Call `db.cancel()` when your application needs to interrupt PostgreSQL, then observe the operation's outcome.
-These resource-package changes are unreleased. The published installation
-versions above do not include this new package arrangement; use a coordinated
-checkout for this section.
+Await `db.close()` during orderly shutdown. It stops new work and drains accepted operations. A failed close leaves the handle terminal. Keep cancellation and shutdown in the application service that owns the handle, not in individual screen render paths.
-The Android Gradle plugin selects initialization resources at build time:
+## Handle failures
-```kotlin
-oliphaunt {
- seedProfile.set("standard") // Or "icu" for an ICU seed and canonical ICU data.
-}
-```
+`PostgresException.postgresError.sqlstate` identifies a PostgreSQL failure. A normal callback exception is rethrown after rollback. If rollback also fails, `OliphauntTransactionRollbackException` exposes both errors; an independent database failure is preserved by `OliphauntTransactionDatabaseException`.
-The default includes no seed. Select one for first-open initialization, or omit
-it when opening existing storage or supplying application-owned resources.
-Runtime libraries, seed carriers, and canonical ICU data are separate packages.
-Actual device qualification of the new seed carriers remains pending.
+| Symptom | Check |
+| --- | --- |
+| Runtime resource is missing | Plugin applied, repositories configured, native app rebuilt |
+| Directory argument does not compile | Pass a `File`, not `.absolutePath` |
+| Root already owned | Existing handle/process and stable app-private path |
+| Extension cannot be created | Gradle selection and open-time selection agree |
+| Decode failure | SQL column type, decoder, and null handling |
diff --git a/src/docs/content/sdk/kotlin/index.mdx b/src/docs/content/sdk/kotlin/index.mdx
index d944632c1..d20fe0411 100644
--- a/src/docs/content/sdk/kotlin/index.mdx
+++ b/src/docs/content/sdk/kotlin/index.mdx
@@ -1,23 +1,15 @@
---
title: Kotlin SDK
-description: Android SDK with coroutine-first database APIs and native resource handling.
+description: Add embedded PostgreSQL to an Android app using coroutine APIs.
---
-
-
-The Kotlin SDK is the Android SDK for Oliphaunt. It provides coroutine-first
-database APIs plus an Android facade for native library loading, runtime asset
-materialization, ABI selection, and app-private storage.
-
-Use this SDK directly from Android apps written with Kotlin, Java interop, or
-Jetpack Compose. React Native on Android delegates runtime work through this SDK,
-so Android packaging, lifecycle, and resource selection are defined here.
+Use `dev.oliphaunt:oliphaunt-android` in Android apps with API level 24 or later. The SDK provides suspend functions and supports `arm64-v8a` and `x86_64` native targets.
## Install
-Add the Android package to your app:
+Ensure `mavenCentral()` is available in both plugin and dependency repositories in `settings.gradle.kts`. Apply the Oliphaunt plugin alongside your app's existing Android/Kotlin plugins:
-```kotlin
+```kotlin title="app/build.gradle.kts"
plugins {
id("com.android.application")
id("dev.oliphaunt.android") version "{{release:oliphaunt-kotlin}}"
@@ -26,61 +18,59 @@ plugins {
dependencies {
implementation("dev.oliphaunt:oliphaunt-android:{{release:oliphaunt-kotlin}}")
}
+```
+
+Select the initialization resources for new Android databases:
+```kotlin title="app/build.gradle.kts"
oliphaunt {
- selectedExtensions.add("vector")
+ seedProfile.set("standard")
}
```
-The Gradle plugin verifies and packages selected native runtime artifacts,
-Android ABIs, and exact extension files. The app ships only the selected
-extensions plus declared dependencies.
+Use `"icu"` instead if your database needs ICU collations. The plugin packages the selected seed and runtime resources. Build and run a native Android application after changing this configuration.
-## Open And Query
+## Run your first query
-Open a database from a coroutine:
+Call this function from a coroutine. It opens disposable storage, binds a value, reads a typed result, and closes the database.
-```kotlin
-import dev.oliphaunt.DatabaseStorage
-import dev.oliphaunt.Oliphaunt
-import dev.oliphaunt.OliphauntExtension
-import dev.oliphaunt.OliphauntConfig
+
-val database = Oliphaunt.open(
- context = applicationContext,
- config = OliphauntConfig(
- storage = DatabaseStorage.Directory(
- applicationContext.filesDir.resolve("main.oliphaunt").absolutePath,
- ),
- extensions = listOf(OliphauntExtension.VECTOR),
- ),
-)
-
-val rows = database.query("SELECT 1::text AS value")
-database.close()
+```kotlin
+import android.content.Context
+import dev.oliphaunt.*
+
+suspend fun firstQuery(context: Context) {
+ val db = Oliphaunt.open(context.applicationContext)
+ try {
+ val result = db.query(
+ "SELECT $1::int4 AS answer",
+ parameters = listOf(QueryParam.int(42)),
+ )
+ println(result.rows[0].value("answer", PostgresDecoders.int)) // 42
+ } finally {
+ db.close()
+ }
+}
```
-## Runtime Shape
+The SDK serializes work on one native PostgreSQL session. Keep the database in application state when multiple coroutines need it.
-Android direct mode owns one resident backend per app process and one serialized
-physical session.
+## Keep data between launches
-Coroutine callers may share a database handle. Direct mode queues work against
-the resident backend and preserves transaction ordering. Android packaging owns
-ABI selection, native library loading, and runtime resource hydration before the
-first open.
+Use this storage configuration instead of the disposable example above. Direct mode stays bound to its first root for the lifetime of the process; closing does not let the same process switch roots.
-## App Responsibilities
+Use an app-private `File` as the persistent root:
-- Store persistent data in app-private storage unless the app deliberately
- exports a backup.
-- Select exact SQL extension names at build/configuration time so the APK or AAB
- contains only selected extension artifacts and declared dependencies.
-- Use SDK backup and restore APIs for archive validation and destination
- materialization.
+```kotlin
+val db = Oliphaunt.open(
+ context = context.applicationContext,
+ config = OliphauntConfig(
+ storage = DatabaseStorage.Directory(context.filesDir.resolve("main.oliphaunt")),
+ ),
+)
+```
-## First Query
+`Directory` accepts `java.io.File`, not a path string. Reopen the same directory to access saved data; the default `TemporaryDirectory` is disposable.
-Use [Build With Kotlin](/docs/sdk/kotlin/guide) for open/query,
-configuration, lifecycle, exact extensions, backup, restore, and troubleshooting.
-Use the [API reference](/docs/sdk/kotlin/api-reference) for the public API map.
+Continue with the [Kotlin guide](/docs/sdk/kotlin/guide), [mobile lifecycle guide](/docs/learn/mobile-stability), or [API reference](/docs/sdk/kotlin/api-reference).
diff --git a/src/docs/content/sdk/react-native/api-reference.md b/src/docs/content/sdk/react-native/api-reference.md
index 950ef2863..1be2f0cea 100644
--- a/src/docs/content/sdk/react-native/api-reference.md
+++ b/src/docs/content/sdk/react-native/api-reference.md
@@ -1,54 +1,45 @@
---
-title: API Reference
-description: React Native SDK API map for TypeScript, config plugin, TurboModule, JSI binary transport, and mobile lifecycle.
+title: React Native API reference
+description: Storage, query methods, transactions, and lifecycle in @oliphaunt/react-native.
---
-# API Reference
-
-This page maps the React Native
-SDK by task.
-
-| Area | Public surface | Use it for |
-| --- | --- | --- |
-| Opening | `Oliphaunt.open`, `OpenConfig`, `DatabaseStorage` | Use temporary storage by default or select an app-data name or directory |
-| Config plugin | Expo plugin options | Include the selected native runtime and exact extension artifacts in iOS and Android builds |
-| Database handle | `OliphauntDatabase` | Keep the opened database in app state and route calls through one native handle |
-| Single-statement SQL | decoded `query`, byte-preserving `queryRaw`, `execute` | Read object or array rows, retain exact wire rows, or assert that a command returns no rows |
-| Multi-statement and metadata | `exec`, `describe` | Return simple-query results in order or resolve parameter/result OIDs without executing |
-| Parameters and codecs | `text`, `binary`, `typedNull`, `json`, `array`, `postgresOids`, per-query encoders and decoders | Use safe scalar inference, deterministic PostgreSQL types, or extension-owned OID codecs |
-| Transactions | callback `transaction`, transaction `rollback`, transaction `closed` | Pin the mobile session for a callback and explicitly roll back without a later commit |
-| Raw protocol | database `execProtocolRaw`, `execProtocolRawStream` | Send PostgreSQL protocol bytes as one result or synchronous callback chunks through JSI `ArrayBuffer`; transaction handles deliberately do not expose this bypass, and callbacks cannot return thenables or reenter the same handle (`cancel` remains out of band) |
-| Lifecycle | read-only `closed`, `cancel`, `close`, `Symbol.asyncDispose` | Cancel remains out of band while the close cutoff drains admitted work, stops at native teardown, and forgotten handles use exact-generation best-effort cleanup |
-| Data movement | `backup`, `restore` | Delegate archive validation and destination materialization to Swift or Kotlin |
-| Diagnostics | query-scoped `notices`, standard `Error`, `PostgresError` | Preserve PostgreSQL notices and SQLSTATE data in TypeScript |
-
-```ts
-const result = await db.query('SELECT $1::int4 AS answer', [41]);
-const answer = result.rows[0]?.answer;
-const fields = (await db.describe('SELECT $1::uuid', [2950])).fields;
-```
-
-The cross-SDK behavior follows the
-[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md).
-
-Inside a callback transaction, do not issue manual `BEGIN`, `START
-TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`.
-Use callback return/throw or `rollback()`; `SAVEPOINT` and `ROLLBACK TO` are
-supported. `ROLLBACK AND CHAIN` is unsupported and wire-indistinguishable from
-`ROLLBACK TO`, so Oliphaunt rejects `ROLLBACK`/`ABORT ... AND CHAIN` before
-dispatch and enforces every other ownership boundary from PostgreSQL response
-frames. A proven escape makes the database close-only and suppresses any
-follow-up SDK transaction command.
-
-After a callback failure, a successful automatic rollback rethrows the original
-value unchanged. If rollback also fails, an `AggregateError` contains the
-callback failure followed by the rollback failure. If the callback throws a
-different value after an earlier independent database or protocol failure
-poisoned or expired ownership, an `AggregateError` contains the callback failure
-followed by that database failure and the database is close-only. Ordinary
-PostgreSQL statement errors that remain safely rollbackable do not automatically
-produce an aggregate.
-
-The React Native SDK owns the JavaScript boundary. Runtime behavior remains
-platform-native: Apple calls flow through Swift, Android calls flow through
-Kotlin.
+Import the default `Oliphaunt` export or the named export from `@oliphaunt/react-native`. The package includes TypeScript declarations.
+
+## Entry points and storage
+
+`Oliphaunt.open(config?)` returns `Promise`. Configuration accepts `storage`, `startupGUCs`, `username`, `database`, `extensions` (typed `NativeExtension` descriptors), and `broker` (timeouts for a broker build).
+
+| Storage value | Lifetime |
+| --- | --- |
+| `{ kind: 'temporaryDirectory' }` | Disposable; default |
+| `{ kind: 'directory', path: string }` | Persistent explicit path |
+| `{ kind: 'applicationData', name: string }` | Persistent platform-resolved app-data path |
+
+`Oliphaunt.restore(destination, bytes, options?)` accepts either persistent storage form and returns `Promise`. The destination must be new or empty. Archive input accepts supported binary buffers and byte arrays.
+
+## Query methods
+
+| Method | Purpose |
+| --- | --- |
+| `query(sql, parameters?, options?)` | Decoded rows and field metadata |
+| `execute(sql, parameters?, options?)` | Command metadata |
+| `queryRaw(sql, parameters?, options?)` | Nullable column bytes and metadata |
+| `exec(sql, options?)` | Multi-statement SQL results |
+| `describe(sql, parameterTypeOids?)` | Statement metadata |
+| `transaction(body)` | Callback-owned transaction |
+
+Query options include positional rows and custom codecs. Duplicate field names require array row mode. Row type annotations do not validate a query's schema at runtime.
+
+Transactions expose typed query methods and `rollback()`. They do not expose raw protocol, backup, or close. Return to commit, throw to roll back, and use the callback handle only during its lifetime. Savepoints are supported; manual outer transaction-lifecycle SQL is not.
+
+## Lifecycle and errors
+
+`backup()` returns `Promise`. `cancel()` requests an interrupt. `close()` returns `Promise`, `closed` reports state, and `Symbol.asyncDispose` supports explicit async disposal where the JavaScript runtime provides it.
+
+`PostgresError` preserves SQLSTATE and backend diagnostics. Composite transaction failures use `AggregateError` with the callback failure followed by the rollback or database failure. Unknown commit outcomes are not automatically retried.
+
+## Raw protocol
+
+`execProtocolRaw` buffers backend frames. `execProtocolRawStream` passes chunks to a synchronous callback returning `undefined`; promises and reentrant query calls are unsupported. Raw protocol requires a protocol-aware caller and is separate from typed row queries.
+
+The native build selects direct or broker mode. Broker mode accepts only `temporaryDirectory` or `applicationData` storage. `broker.startupTimeoutMs` and `broker.operationTimeoutMs` accept positive integer milliseconds. Broker failures expose `reason`, `execution`, and `requiresReopen`; an `unknown` execution outcome must not be retried blindly. There is no local server API. See [native integration](/docs/sdk/react-native/architecture) for packaging and runtime behavior.
diff --git a/src/docs/content/sdk/react-native/architecture.mdx b/src/docs/content/sdk/react-native/architecture.mdx
index 4e788b2e0..95fe52a7a 100644
--- a/src/docs/content/sdk/react-native/architecture.mdx
+++ b/src/docs/content/sdk/react-native/architecture.mdx
@@ -1,86 +1,59 @@
---
-title: Architecture
-description: How React Native delegates native PostgreSQL behavior to Swift and Kotlin while owning the TypeScript and app-build boundary.
+title: Native integration
+description: Configure native builds, runtime resources, and process isolation for a React Native app.
---
-# Architecture
+The React Native package uses Swift on iOS and Kotlin on Android. It supplies TypeScript APIs over the same native PostgreSQL runtime used by those platform SDKs.
-`@oliphaunt/react-native` is the New Architecture adapter over the Swift SDK on
-Apple platforms and the Kotlin SDK on Android.
+## Choose a runtime mode
-
+Direct mode is the default. Use one application-owned handle and share it through a service. For process isolation, select broker mode when configuring the native build; follow [mobile broker setup](/docs/learn/mobile-stability#broker-mode).
-## Ownership
+Both modes run database work away from JavaScript and return promises. They provide one PostgreSQL session, not a connection pool.
-| Layer | Owns |
-| --- | --- |
-| React Native package | TypeScript API, config plugin, TurboModule schema, JSI byte transport, installed app wiring |
-| Swift SDK | Apple storage, cluster-seed hydration, native direct lifecycle, queries, extensions, backup/restore |
-| Kotlin SDK | Android storage, cluster-seed hydration, native direct lifecycle, queries, extensions, backup/restore |
-| `liboliphaunt` | Embedded PostgreSQL lifecycle, raw protocol, cancellation, direct ownership, physical archive |
+## Expo integration
-The adapter does not duplicate runtime behavior or add broker/server modes.
-Platform-native applications and React Native applications therefore use the
-same direct-mode semantics on each mobile OS.
+The [quickstart](/docs/sdk/react-native) uses the config plugin to prepare native projects. The plugin stages iOS runtime resources, configures local CocoaPods dependencies, and applies the Android Gradle integration. Expo Go cannot load this custom native module.
-## JavaScript surface
+For an existing Expo native project, rerun prebuild when the plugin configuration changes, then rebuild the app. Review generated native changes alongside any native customizations you maintain.
-```ts
-import Oliphaunt from '@oliphaunt/react-native';
+## Native projects managed directly
-await using database = await Oliphaunt.open({
- storage: { kind: 'applicationData', name: 'main' },
- startupGUCs: { application_name: 'mobile-app' },
-});
+Use the package's same platform integration when maintaining native projects without Expo prebuild. Match versions to the installed React Native package rather than mixing platform SDK releases.
-const result = await database.query('SELECT 1::text AS value');
+On Android, add `mavenCentral()` to plugin and dependency repositories and apply the `dev.oliphaunt.android` plugin to the app module using version `{{release:oliphaunt-kotlin}}`. The React Native package supplies its Kotlin dependency. Set `seedProfile.set("standard")` in the app's `oliphaunt` block for a new database. Configure selected extensions there and rebuild.
+
+The manual steps below configure direct mode. On iOS, set deployment target 17.0 or later and install the standard seed dependency shown in the quickstart. The npm package includes local `COliphaunt` and `Oliphaunt` podspecs plus a staging tool. Before running CocoaPods, stage the app payload using the package's exported integration helper. Save this script in your app root and run it with Node:
+
+```js title="prepare-oliphaunt.mjs"
+import fs from 'node:fs';
+import path from 'node:path';
+import { createRequire } from 'node:module';
+const require = createRequire(import.meta.url);
+const packageRoot = path.dirname(require.resolve('@oliphaunt/react-native/package.json'));
+const plugin = require(path.join(packageRoot, 'app.plugin.js'));
+const options = plugin.normalizeOptions({ seedProfile: 'standard', extensions: [] });
+const iosRoot = path.resolve('ios');
+await plugin.stageIosAppPayload(process.cwd(), iosRoot, options);
+const podfile = path.join(iosRoot, 'Podfile');
+fs.writeFileSync(
+ podfile,
+ plugin.insertIosPodfileBlock(fs.readFileSync(podfile, 'utf8'), options),
+);
```
-The public surface is open, typed query/execute, buffered and callback-streamed
-raw protocol, transaction, cancellation, physical backup, static
-restore, and close. There is no app-background mode.
-
-Every operation returns a JavaScript promise. JSI performs the required binary
-copy and callback registration, then delegates PostgreSQL and filesystem work
-to the Swift or Kotlin SDK's serial native owner. Module invalidation stops
-callback delivery to the retiring JSI runtime and schedules native close
-asynchronously; it never waits on the JavaScript, iOS main, or Android UI
-thread. A thrown raw-stream callback rejects the operation before the owner
-admits subsequent work. Chunk delivery is a synchronous backpressure boundary:
-returning a Promise or thenable, or reentering the same database or transaction
-from the callback, rejects the stream. The original callback error is preserved
-only after native recovery confirms a known PostgreSQL protocol boundary; an
-execution, transport, or recovery failure is authoritative instead and poisons
-the database. A recovered callback-only failure leaves the handle reusable; a
-buffered raw-protocol rejection poisons it because the session outcome is
-unknown. `cancel()` remains independently admitted so it can interrupt active
-native work. It remains callable after close admission while earlier FIFO work
-drains and stops at native teardown.
-
-## Binary transport
-
-Raw protocol and archive bytes use the JSI `ArrayBuffer` path. Small
-configuration and handle-lifecycle calls use the TurboModule boundary. The
-transport preserves typed-array offsets and explicit ownership, keeping
-payloads binary end to end.
-
-## Storage and lifecycle
-
-Omitted storage uses an SDK-owned temporary directory. `applicationData(name)`
-lets native platform code resolve an app-private path; `directory(path)` is for
-applications that already own one. Each path names a managed root, not PGDATA.
-
-The bridge owns one mobile direct database at a time. It rejects another open
-while one is pending, active, or closing. App lifecycle policy calls `cancel()`
-or `close()` explicitly. A JavaScript finalizer can only request cleanup of the
-exact process-unique generation it owned, so stale cleanup cannot affect a
-newer native session; module invalidation remains the fallback. Restore accepts
-a new or existing-empty destination and does not replace data.
-
-## Extensions and packaging
-
-The config plugin uses the app's Expo autolinker to discover installed resource
-packages at build time. Both native platforms resolve those same package paths;
-the existing carrier checks validate their versions and contents. Optional plugin
-filters can narrow what ships. `open()` selects typed extension descriptors for
-each database, and PostgreSQL `CREATE EXTENSION` remains the SQL activation step.
+The Podfile must already call `use_native_modules!`. The helper adds the local platform podspecs and staged payload dependency. Run `bundle exec pod install` from `ios`, then rebuild the app. Keep this preparation step in the application's native build process.
+
+## Extension resources
+
+Install the native extension packages your app uses before plugin or manual setup. For example:
+
+```sh
+npm install @oliphaunt/extension-vector@{{release:oliphaunt-extension-vector}}
+```
+
+The Expo plugin discovers installed extension packages. You can narrow the packaged selection with its `extensions` filter. Pass imported extension descriptors to `Oliphaunt.open({ extensions: [...] })`. Selection at runtime verifies the installed resources; it cannot add missing native code. See the [extension recipe](/docs/sdk/react-native/guide#add-an-extension).
+
+## Lifecycle
+
+Explicitly await `close()` to observe cleanup. Module invalidation and finalizers provide fallback cleanup only. Cancel active SQL through `cancel()`, then observe its outcome. The app remains responsible for backgrounding policy and persistent storage; see [Ship a mobile database](/docs/learn/mobile-stability).
diff --git a/src/docs/content/sdk/react-native/guide.mdx b/src/docs/content/sdk/react-native/guide.mdx
index 65be207e4..4dfdb6d21 100644
--- a/src/docs/content/sdk/react-native/guide.mdx
+++ b/src/docs/content/sdk/react-native/guide.mdx
@@ -1,232 +1,106 @@
---
-title: Build With React Native
-description: Install the React Native package, build a native app binary, configure exact extensions, use JSI transport, and own app lifecycle policy.
+title: React Native guide
+description: Use queries, transactions, extensions, backups, and lifecycle in a mobile application.
---
-# Build With React Native
+These recipes use an open `db` from the [React Native quickstart](/docs/sdk/react-native). Keep database ownership in an application service; components call that service.
-Use the React Native SDK in Expo and New Architecture React Native apps. The JS
-package owns TypeScript DX, config plugin behavior, TurboModule/JSI transport,
-and installed-app integration. Runtime behavior is delegated to Swift on Apple
-platforms and Kotlin on Android.
+## Query application data
-
-Oliphaunt includes Swift and Kotlin runtime code. Use an Expo development build
-or a React Native app binary so the native runtime is present when JavaScript
-loads.
-
+```ts
+await db.execute('CREATE TABLE IF NOT EXISTS notes (body text NOT NULL)');
+await db.execute('INSERT INTO notes (body) VALUES ($1)', ['First note']);
+const result = await db.query('SELECT body FROM notes');
+console.log(result.rows);
+```
+
+Use `$1` parameters for user-supplied values. `query` returns decoded rows; `execute` returns command metadata. Use `rowMode: 'array'` when a query has duplicate column names.
-
+## Run a transaction
-
-
+```ts
+await db.transaction(async (tx) => {
+ await tx.execute('INSERT INTO notes (body) VALUES ($1)', ['First']);
+ await tx.execute('INSERT INTO notes (body) VALUES ($1)', ['Second']);
+});
+```
-### Install
+Returning commits; throwing rolls back. All callback queries must use `tx`. Do not send manual transaction-lifecycle SQL or call the outer `db`. Use `tx.rollback()` for explicit rollback; savepoints are supported.
-Install the package for the app path you own, then build the native app binary.
-The runtime uses Swift and Kotlin code, so package installation alone is not the
-last step. The installed app must contain the native module and selected runtime
-resources before JavaScript calls `Oliphaunt.open()`.
+## Add an extension
-Expo apps:
+Install the native extension package, then select it in the Expo plugin configuration before building:
```sh
-npx expo install @oliphaunt/react-native@{{release:oliphaunt-react-native}}
-npx expo prebuild
-npx expo run:ios
-npx expo run:android
+npm install @oliphaunt/extension-vector@{{release:oliphaunt-extension-vector}}
```
-Install the extension packages your app needs, such as
-`@oliphaunt/extension-vector`, and enable the Expo config plugin. Prebuild
-discovers installed extensions and `@oliphaunt/icu` automatically.
-
```json
{
"expo": {
- "plugins": ["@oliphaunt/react-native"]
+ "plugins": [["@oliphaunt/react-native", { "extensions": ["vector"] }]]
}
}
```
-Discovery uses the app's [Expo autolinker](https://docs.expo.dev/modules/autolinking/),
-including transitive dependencies, workspace links, search paths, and platform
-exclusions. Install packages under their published names and deduplicate any
-conflicting resource versions. The optional `extensions` plugin setting limits
-which SQL members ship; `icu: false` disables ICU packaging unless an ICU seed
-requires it. Omit these settings for automatic discovery. Installing the contrib
-package ships all its members
-unless you provide an `extensions` filter.
-
-React Native apps without Expo still use the same package, but native projects
-own the equivalent Pod, Gradle, and resource configuration. Rebuild after
-changing native runtime or extension selection because those choices affect the
-installed app binary.
-
-
-
-
-### Open and query
-
-Open a database from TypeScript, run SQL, and close it when the app no longer
-needs the handle.
+Rebuild the native app, then import its descriptor when opening:
```ts
-import Oliphaunt, { extensions } from '@oliphaunt/react-native';
+import vector from '@oliphaunt/extension-vector';
const db = await Oliphaunt.open({
storage: { kind: 'applicationData', name: 'main' },
- extensions: [extensions.vector],
+ extensions: [vector],
});
-
-const rows = await db.query('SELECT 1::text AS value');
-const value = rows.rows[0]?.value;
-
-await db.close();
+await db.execute('CREATE EXTENSION IF NOT EXISTS vector');
```
-Keep the database object in app state or a service object and share references
-to that object. A second `Oliphaunt.open()` is rejected while the native direct
-session is opening, active, or closing; call it again only after `close()`
-completes.
+The plugin packages selected extension resources and dependencies. Extension changes require a native rebuild; a JavaScript update alone cannot add them. For ICU collations, replace the standard seed dependency with `@oliphaunt/seed-native-ios-datum64-icu` and install `@oliphaunt/icu`; use matching database-resource versions.
-
-
+## Choose process isolation
-### Create app data
+The quickstart uses direct mode. For a separate database process, follow [mobile broker setup](/docs/learn/mobile-stability#broker-mode). Broker mode requires its own storage and restore path; use the recipes below for direct mode.
-Use the SQL helpers for application queries. This keeps most React Native code
-away from PostgreSQL protocol details:
+## Back up and restore
-```ts
-await db.execute(`
- CREATE TABLE IF NOT EXISTS notes (
- id bigserial PRIMARY KEY,
- title text NOT NULL,
- body text NOT NULL,
- created_at timestamptz NOT NULL DEFAULT now()
- )
-`);
-
-await db.query(
- 'INSERT INTO notes (title, body) VALUES ($1, $2) RETURNING id::text AS id',
- ['First note', 'Stored by embedded PostgreSQL'],
-);
+Direct mode stays bound to one database root and configuration for the lifetime of the application process. Closing a handle does not let that process switch to another root. Prepare the restored data, then use it on the next launch.
-const notes = await db.query(
- 'SELECT id, title FROM notes ORDER BY id DESC LIMIT 20',
+```ts
+const archive = await db.backup();
+await db.close();
+await Oliphaunt.restore(
+ { kind: 'applicationData', name: 'restored' },
+ archive,
);
-const firstTitle = notes.rows[0]?.title;
```
-For callback transactions, a callback failure is rethrown unchanged after
-automatic rollback succeeds. If rollback also fails, `AggregateError.errors`
-contains the callback failure followed by the rollback failure. If the callback
-throws a different value after an earlier independent database or protocol
-failure poisoned or expired transaction ownership, the aggregate instead
-contains the callback failure followed by that database failure and the database
-is close-only. This independent-failure case does not include an ordinary
-PostgreSQL statement error that remains safely rollbackable.
-
-Reach for the buffered raw protocol API only when building adapters that need
-PostgreSQL wire messages directly.
-
-
-
-
-### Configure
-
-Configure storage, selected exact extensions, PostgreSQL startup GUCs, and
-startup identity through the JS API. Installed resource packages determine what
-ships in the app bundle; runtime storage controls where app data lives.
+On a subsequent application launch, open the restored destination:
-Keep build-time and runtime settings separate. The config plugin controls native
-artifacts in the installed app. `Oliphaunt.open()` controls storage, startup
-identity, GUCs, and extension activation for that app run. Omit `storage` for an
-SDK-owned temporary directory. Use
-`{ kind: 'applicationData', name: 'main' }` for normal persistent mobile data,
-or `{ kind: 'directory', path }` when the app already owns a platform path.
-
-
-
-
-### Choose a mode
-
-React Native uses native direct on mobile. Database work is delegated to Swift
-on Apple platforms and Kotlin on Android.
-
-
-
-
-### Use binary transport
-
-New Architecture builds use binary ArrayBuffer/JSI transport for buffered raw
-protocol bytes. Bulk payloads stay in binary buffers.
-
-Treat JSI transport as the bulk-byte boundary. Small configuration and lifecycle
-calls use the TurboModule API; buffered protocol payloads stay in binary
-buffers.
-
-
-
-
-### Handle lifecycle
-
-Use `cancel()` and `close()` explicitly from app lifecycle policy. `cancel()`
-remains available while a close cutoff drains earlier admitted work and stops
-when native teardown begins. Forgotten JavaScript handles schedule
-generation-bound best-effort cleanup, but explicit close remains deterministic.
-Direct mobile mode can logically reopen inside one resident app process.
-
-
-
-
-### Select extensions
-
-Select exact SQL extension names in configuration. The native app packages
-include only selected extensions plus declared dependencies. `CREATE EXTENSION`
-succeeds when the selected runtime resources contain that extension for the
-target platform.
+```ts
+const restored = await Oliphaunt.open({
+ storage: { kind: 'applicationData', name: 'restored' },
+});
+await restored.close();
+```
-
-
+Restore requires new or empty persistent storage. It cannot target temporary storage. Reapply required extensions when opening the restored database. Keep physical restores within a compatible native runtime family.
-### Back up and restore
+## Handle lifecycle and errors
-Use the React Native backup and restore APIs instead of copying platform storage
-directories from JavaScript. The SDK delegates archive validation and destination
-materialization to Swift or Kotlin, so platform storage rules stay native.
-Restore accepts a new or existing-empty destination and rejects nonempty data
-without mutation.
+Call `db.cancel()` to request interruption of active SQL, and await the query's outcome. Cancelling a JavaScript promise does not interrupt PostgreSQL.
-
-
+Await `db.close()` when your application finishes using the database. It stops new work and drains accepted operations. Garbage collection and native module invalidation provide fallback cleanup, but they cannot report shutdown errors to your app.
-
+A SQL failure is a `PostgresError` with SQLSTATE. Transaction failures roll back when possible; an `AggregateError` preserves the callback and rollback/database failures when both matter. After a terminal protocol error, close and reopen persistent storage rather than reusing the handle.
## Troubleshooting
-Check the development build, Expo config plugin output, autolinking,
-TurboModule codegen, native module availability, selected extension artifacts,
-and platform SDK errors. For database runtime behavior, follow the Swift or
-Kotlin SDK page for the target platform.
-
-## Development resource packaging
-
-These resource-package changes are unreleased. The published installation
-versions above do not include this new package arrangement; use a coordinated
-checkout for this section.
-
-For Android, the Expo plugin selects one resource profile at build time:
-
-```json
-{ "plugins": [["@oliphaunt/react-native", { "seedProfile": "icu" }]] }
-```
+| Symptom | Check |
+| --- | --- |
+| Native module is unavailable | New Architecture enabled and a native build installed |
+| Works in development, fails in the app | Runtime resources and extensions are packaged for that platform |
+| Changes disappear after restart | Use `applicationData` or `directory`, not temporary storage |
+| A transaction waits | Use only `tx` for its SQL |
+| Extension changes have no effect | Rebuild the native application |
-For iOS, select exactly one development npm carrier:
-`@oliphaunt/seed-native-ios-datum64-standard` or
-`@oliphaunt/seed-native-ios-datum64-icu` and set the matching `seedProfile`.
-The plugin adds its resource CocoaPod. Install `@oliphaunt/icu` for an ICU
-database; the plugin discovers it without an additional flag. These are app
-packaging choices, not JavaScript database-open modes. Existing storage does not require a seed.
-Mobile device qualification of the new seed carriers remains pending.
+See [Ship a mobile database](/docs/learn/mobile-stability) for backgrounding and recovery guidance.
diff --git a/src/docs/content/sdk/react-native/index.mdx b/src/docs/content/sdk/react-native/index.mdx
index 7eb14b468..f82a9716b 100644
--- a/src/docs/content/sdk/react-native/index.mdx
+++ b/src/docs/content/sdk/react-native/index.mdx
@@ -1,36 +1,19 @@
---
title: React Native SDK
-description: New Architecture package with Expo config plugin, TurboModule, and JSI transport.
+description: Run PostgreSQL in an iOS or Android app using TypeScript and native platform SDKs.
---
-
+Use `@oliphaunt/react-native` with React Native's New Architecture on iOS or Android. The current package requires React Native 0.85+ and React 19+. Expo integration requires Expo 56+ and a native development or production build; Expo Go does not include this native module.
-The React Native SDK is a New Architecture package over the Swift and Kotlin
-SDKs. It provides TypeScript APIs, an Expo config plugin, TurboModule codegen,
-and JSI ArrayBuffer transport while native execution stays in the platform SDKs.
-
-Use this package for Expo development builds and React Native New Architecture
-apps on iOS and Android. Apple runtime behavior flows through the Swift SDK;
-Android runtime behavior flows through the Kotlin SDK. The JavaScript package
-owns TypeScript ergonomics, config plugin output, binary transport, and
-installed-app integration.
-
-## Install
-
-Install the package and build a development client or native app binary:
+## Install and build
```sh
-npx expo install @oliphaunt/react-native@{{release:oliphaunt-react-native}}
+npm install @oliphaunt/react-native@{{release:oliphaunt-react-native}} @oliphaunt/seed-native-ios-datum64-standard@{{release:database-resources}}
```
-Oliphaunt includes native Swift and Kotlin code, so React Native apps run it
-from an Expo development build or a native app binary. The config plugin
-discovers installed extension and ICU packages for the native app build.
-
-Install the extension packages you use, such as `@oliphaunt/extension-vector`,
-and enable the plugin:
+The seed package supplies the initial empty database for iOS; the plugin selects matching initialization resources on Android. For an Expo app, add the config plugin:
-```json
+```json title="app.json"
{
"expo": {
"plugins": ["@oliphaunt/react-native"]
@@ -38,52 +21,59 @@ and enable the plugin:
}
```
-Rebuild the development client or native app binary after changing native
-runtime or extension selections.
+Build the native app for the platform you are testing:
-## Open And Query
+
+
-Open from TypeScript and keep the handle in app state, a data service, or a
-provider that matches your navigation lifetime:
-
-```ts
-import Oliphaunt, { extensions } from '@oliphaunt/react-native';
+```sh
+npx expo run:ios
+```
-const db = await Oliphaunt.open({
- storage: { kind: 'applicationData', name: 'main' },
- extensions: [extensions.vector],
-});
+
+
-const rows = await db.query('SELECT 1::text AS value');
-await db.close();
+```sh
+npx expo run:android
```
-Use high-level SQL helpers for app code. Use the buffered raw protocol API
-when building adapters that need PostgreSQL wire messages directly.
+
+
-## Runtime Shape
+If you manage native projects directly, integrate the package's iOS CocoaPods and Android Gradle setup as described in [native integration](/docs/sdk/react-native/architecture). Rebuild after changing native resources or extensions.
-React Native owns the JavaScript boundary: typed configuration, SQL helpers,
-raw protocol bytes, backup/restore, and explicit lifecycle operations.
-Apple calls flow through Swift; Android calls flow through Kotlin.
+## Run your first query
-Direct mobile mode owns one resident backend per app process and one serialized
-physical PostgreSQL session. Multiple JavaScript calls can share a handle and
-are queued through the platform SDK.
+Call this function from application initialization or a user action, not during React rendering:
-## App Responsibilities
+
-- Build with a native app binary or development client.
-- Omit `storage` for temporary work, or select `applicationData` for persistent
- app data without constructing platform-specific paths.
-- Select exact SQL extension names so only selected extension artifacts and
- declared dependencies enter the iOS or Android app artifact.
-- Use SDK backup and restore APIs for user-visible export/import flows instead
- of copying platform storage directories from JavaScript.
+```ts
+import Oliphaunt from '@oliphaunt/react-native';
+
+export async function firstQuery() {
+ const db = await Oliphaunt.open();
+ try {
+ const result = await db.query('SELECT $1::int4 AS answer', [42]);
+ console.log(result.rows[0]?.answer); // 42
+ } finally {
+ await db.close();
+ }
+}
+```
+
+## Keep data between launches
+
+Use this storage configuration instead of the disposable example above. Direct mode stays bound to its first root for the lifetime of the process; closing does not let the same process switch roots.
+
+Let the platform SDK choose an app-private directory by name:
+
+```ts
+const db = await Oliphaunt.open({
+ storage: { kind: 'applicationData', name: 'main' },
+});
+```
-## First Query
+Keep this handle in an application service. Reopen the same name to use its data again. The default temporary storage is disposable.
-Use [Build With React Native](/docs/sdk/react-native/guide) for Expo setup, first
-query, config plugin options, JSI transport, lifecycle, extensions, and backup.
-Use the [architecture](/docs/sdk/react-native/architecture) page for the native
-boundary model.
+Continue with the [React Native guide](/docs/sdk/react-native/guide) or [API reference](/docs/sdk/react-native/api-reference).
diff --git a/src/docs/content/sdk/rust/api-reference.md b/src/docs/content/sdk/rust/api-reference.md
index 981dc5ef8..f88635193 100644
--- a/src/docs/content/sdk/rust/api-reference.md
+++ b/src/docs/content/sdk/rust/api-reference.md
@@ -1,80 +1,63 @@
---
-title: API Reference
-description: Rust SDK API map for builders, runtime modes, query results, lifecycle, and data movement.
+title: Rust API reference
+description: Native Rust entry points, builder options, queries, transactions, and ownership.
---
-# API Reference
+The `oliphaunt` crate exports synchronous and asynchronous database APIs. Start with the [quickstart](/docs/sdk/rust) for a complete program.
-Use the Rust API reference for exact signatures. This page maps the public
-surface so you can jump from a product concept to the item you need.
+## Database types
-| Area | Public surface | Use it for |
+| Type | Ownership | Execution |
| --- | --- | --- |
-| Calling shape | database `Oliphaunt`, `AsyncOliphaunt`; lifecycle `OliphauntServer`, `AsyncOliphauntServer` | Block the caller directly, or choose cloneable async handles backed by a dedicated owner thread |
-| Opening | database `open()`, server `start()`, type-associated `builder()`, `DatabaseStorage` | Use the default temporary direct database, configure direct/broker databases, or start a local server through its dedicated builder |
-| Topology | database `direct()`, `broker()`, `open()`; server `OliphauntServer::builder().start()` | Choose an in-process database, broker process, or endpoint/lifecycle-only local-server handle without mixing topology-specific options |
-| Single-statement SQL | `query`, `execute`, parameterized variants, fluent `sql(...).bind(...)` | Return a row-shaped result or assert that one extended-query command returns no rows |
-| Multi-statement and metadata | `exec`, `describe`, fluent `sql(...).describe()` | Return ordered simple-query results or resolve parameter/result OIDs without executing; use the fluent form for typed parameters |
-| Parameters and rows | `TypeOid`, `Parameter`, `IntoParameter`, `ValueFormat`, `QueryRow::try_get`, `FromSql` | Encode typed/null values and decode by OID-validated index or unambiguous name while retaining raw bytes |
-| Raw protocol | `exec_protocol_raw`, `exec_protocol_raw_stream`, `RawStreamResult`, `RawStreamError` | Send PostgreSQL protocol bytes as one owned response, or return bounded chunks to an infallible `()` or typed `Result<(), E>` callback |
-| Transactions | callback `transaction`, `TransactionResult`, `TransactionError`, `Transaction::rollback`, `Transaction::is_closed` | Pin the physical session, use `?` with `E: From`, and retain typed business plus settlement failures |
-| Lifecycle | database `is_closed`, `cancel`, root `cancel_handle`, `close`; server `connection_string`, `is_closed`, `close` | Observe terminal retirement, interrupt database work out of band, connect external server clients, and close synchronously or at the async owner FIFO boundary |
-| Data movement | database `backup`, static `Oliphaunt::restore` | Export and restore the one embedded physical archive |
-| Optional tools | `pg_dump`, `psql`, `PgDumpOptions`, `PsqlOptions` from `oliphaunt-tools` | Run standard logical tools against a native server connection string without adding tools to the core SDK |
-| Diagnostics | result `notices`, opaque `Error`, non-exhaustive `ErrorKind`, `PostgresError`, `TransactionError`, `RawStreamError`, `DecodeError` | Match stable recovery categories while preserving SQLSTATE, callback, settlement, and codec failures without conflation |
-
-```rust
-let result = db
- .sql("SELECT $1::int4 AS answer")
- .bind(41_i32)
- .query()?;
-let answer: i32 = result.rows()[0].try_get("answer")?;
-```
-
-Root database and server lifecycle handles are exclusive and `Send + !Sync`.
-Database operations and synchronous server close use exclusive ownership.
-Ownership may move between threads, but the same owner cannot be shared
-concurrently. Calls block until completion without first dispatching through an
-async SDK owner. Server handles expose no hidden SQL, transaction, raw-protocol,
-or cancellation session; use a PostgreSQL client through `connection_string()`.
-In native direct mode,
-`liboliphaunt` owns PostgreSQL execution on its backend thread, so synchronous
-describes the caller's wait rather than PostgreSQL's OS-thread placement.
-Raw-stream callbacks execute inline and may borrow caller state.
-Their original panic is resumed only after the adapter confirms
-`ReadyForQuery`; an independent recovery failure is returned instead and makes
-the session close-only.
-Use `|chunk| { consume(chunk); }` for infallible delivery. A fallible callback
-returns a concrete `Result<(), E>`; a recovered error is
-`RawStreamError::Callback(E)`. On the async owner thread, a panic after confirmed
-recovery is `CallbackPanicked` and the session remains reusable. A simultaneous
-runtime/recovery failure is always `Database` and poisons the session.
-Obtain a root `CancelHandle` before entering a long call when another thread
-must be able to interrupt it.
-
-`AsyncOliphaunt` handles are cloneable and `Send + Sync`. A method future is
-`Send` when its captured inputs, callback, and output are `Send`; raw-stream
-callbacks run on the owner thread and therefore must be `Send + 'static`.
-Callback panics resolve as SDK errors after confirmed
-recovery rather than unwinding on the awaiting thread. One async handle still represents one serialized
-PostgreSQL session rather than a connection pool. Ordinary work awaits fair,
-bounded admission before entering the owner FIFO; saturation suspends the
-future instead of returning a queue-full error.
-
-Transaction callbacks return ordinary `Result` with `E: From`.
-`TransactionError::CallbackAndRollback` means rollback was sent and failed;
-`CallbackAndDatabase` means an independent database or raw-protocol failure
-expired the transaction and no rollback was sent. The corresponding accessors
-preserve that distinction.
-Managed transaction handles omit raw protocol and do not support manual
-transaction-lifecycle SQL or `AND CHAIN`; use callback return, `rollback()`, or
-a root raw-protocol adapter that owns the complete lifecycle. Savepoints and
-`ROLLBACK TO SAVEPOINT` remain valid.
-
-The cross-SDK behavior follows the
-[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md).
-
-The Rust SDK is the full native topology surface for Tauri and Rust desktop
-apps. Use server mode when you need independent PostgreSQL clients. Choosing an
-`Async*` type changes calling shape and scheduling, not topology or session
-cardinality.
+| `Oliphaunt` | Exclusive, `Send`, not `Sync` | Blocks the caller |
+| `AsyncOliphaunt` | Cloneable, `Send + Sync` | Work runs on an SDK thread |
+| `OliphauntServer` | Server lifecycle owner | PostgreSQL clients use its endpoint |
+| `AsyncOliphauntServer` | Async server lifecycle owner | PostgreSQL clients use its endpoint |
+
+Async clones share one PostgreSQL session. They are not a connection pool.
+
+## Open and configure
+
+`Oliphaunt::open()` creates a temporary direct database. `Oliphaunt::builder()` configures storage and selects `direct().open()` or `broker().open()`. `AsyncOliphaunt` exposes the corresponding async open methods.
+
+`DatabaseStorage::TemporaryDirectory` is disposable; `DatabaseStorage::Directory(PathBuf)` persists data. Builder configuration includes startup PostgreSQL settings, username/database, and exact `Extension` selections. Fresh storage starts with the `postgres` user and database; setting a username does not create a role.
+
+Server builders terminate with `start()`. Listener and server executable options belong to server builders; the broker executable option belongs to broker mode.
+
+## Queries and results
+
+| Operation | Purpose |
+| --- | --- |
+| `query(sql)` | Buffered typed rows |
+| `query_with_params(sql, params)` | Query with parameters |
+| `execute(sql)` / `execute_with_params(sql, params)` | Command metadata |
+| `sql(sql).bind(value).query()` / `.execute()` | Fluent typed parameters |
+| `exec(sql)` | Multiple SQL statements |
+| `describe(sql)` | Statement metadata |
+| `transaction(callback)` | Callback-owned transaction |
+
+Use `QueryResult::rows()` and `Row::try_get` to decode columns by name or index. The PostgreSQL type and requested Rust type must be compatible; represent nullable values with `Option`.
+
+## Transactions and errors
+
+A transaction exclusively owns the session until settlement. Its typed operations omit raw protocol access. Return a result or use its rollback method; manual outer transaction-control SQL is unsupported. Savepoints are allowed.
+
+`TransactionResult` preserves your callback error type. `TransactionError::CallbackAndRollback` retains both failures when rollback was sent and failed. `CallbackAndDatabase` retains an independent database failure that invalidated ownership without sending another rollback. A normal statement error can still be rolled back safely.
+
+Use structured PostgreSQL error fields, including SQLSTATE, to classify database errors. A transport or protocol-recovery failure can leave a handle close-only.
+
+## Backup and lifecycle
+
+`backup()` returns archive bytes. `Oliphaunt::restore(destination, bytes)` restores into new or empty storage; the async type has an async restore operation. Native direct and broker use the same archive family.
+
+`close()` reports teardown errors and makes the handle terminal. `is_closed()` reports its state. Use `cancel_handle()` for out-of-thread cancellation of synchronous work, or `cancel().await` on the async type.
+
+Server handles expose `connection_string()`, closed state, and close. Querying, pooling, and logical tools use ordinary PostgreSQL connections.
+
+## Raw protocol
+
+Buffered and callback-streamed raw protocol APIs are intended for protocol integrations. Root callbacks can borrow caller state; async callbacks must be `Send + 'static`. Callbacks provide synchronous backpressure. Do not re-enter the same database from a callback.
+
+`RawStreamError` distinguishes callback failure from database/recovery failure. A confirmed recovery permits reuse; an independent protocol failure takes precedence and can make the database close-only.
+
+See the [Rust guide](/docs/sdk/rust/guide) for transactions, backups, and runtime recipes.
diff --git a/src/docs/content/sdk/rust/guide.mdx b/src/docs/content/sdk/rust/guide.mdx
index 00c750632..4fedf18ee 100644
--- a/src/docs/content/sdk/rust/guide.mdx
+++ b/src/docs/content/sdk/rust/guide.mdx
@@ -1,294 +1,125 @@
---
-title: Build With Rust
-description: Use the Rust SDK in Tauri or native Rust apps with direct, broker, server, explicit storage, exact extensions, lifecycle, and backup APIs.
+title: Rust guide
+description: Use parameters, transactions, runtime modes, extensions, and backups in Rust.
---
-# Build With Rust
+These recipes use the synchronous native API from the [Rust quickstart](/docs/sdk/rust). Its async counterpart provides the same application operations with `.await`.
-Use the Rust SDK in Tauri backends and native Rust desktop apps. It owns the
-complete native mode model: direct for lowest latency, broker for helper-process
-isolation, and server when independent PostgreSQL clients are required.
+## Query application data
-Calling shape is a separate choice. Root `Oliphaunt` is synchronous and blocks
-the caller until the selected runtime completes, without first dispatching
-through an async SDK owner. In native direct mode, `liboliphaunt` owns
-PostgreSQL execution on its backend thread.
-Root `AsyncOliphaunt` owns a dedicated SDK thread and exposes the same concepts
-through async methods.
+With an open mutable `db`, create a table and insert a parameterized value:
-
-Use this guide when the app runtime is Rust. Tauri webviews and desktop
-JavaScript apps use their SDKs and call into Rust through app commands or helper
-processes.
-
-
-
+```rust
+db.execute("CREATE TABLE IF NOT EXISTS notes (id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, body text NOT NULL)")?;
+let inserted = db
+ .sql("INSERT INTO notes (body) VALUES ($1) RETURNING id")
+ .bind("First note")
+ .query()?;
+let id: i64 = inserted.rows()[0].try_get("id")?;
+```
-
-
+Use `query` for rows and `execute` for command metadata. `sql(...).bind(...)` builds typed parameters; `query_with_params` and `execute_with_params` are also available. Match Rust types to PostgreSQL result types when calling `try_get`.
-### Install
+## Run a transaction
-Add the crate and let the SDK resolve released runtime assets and helpers
-through configuration:
+Use the callback's transaction handle for all statements:
-```toml
-[dependencies]
-oliphaunt = "={{release:oliphaunt-rust}}"
-oliphaunt-extension-vector = "={{release:oliphaunt-extension-vector}}"
+```rust
+db.transaction(|tx| {
+ tx.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["First"])?;
+ tx.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["Second"])?;
+ Ok::<_, oliphaunt::Error>(())
+})?;
```
-
-
+Returning `Ok` commits; returning `Err` rolls back. Callback errors can use your own type if it implements `From`. Do not send manual transaction-lifecycle SQL inside the callback. Use the transaction's rollback API; savepoints are supported.
-### Open and query
-
-Add `oliphaunt-extension-vector` as a Cargo dependency to select its packaged resources.
-
-Create a builder, choose storage, select exact extensions, open, query, and
-close.
+For the async API, use an async closure:
```rust
-use oliphaunt::{DatabaseStorage, Oliphaunt};
-
-fn open_database() -> oliphaunt::Result<()> {
- let mut db = Oliphaunt::builder()
- .storage(DatabaseStorage::Directory(".oliphaunt".into()))
- .direct()
- .extension(oliphaunt_extension_vector::VECTOR)
- .open()?;
-
- let rows = db.query("SELECT 1::text AS value")?;
- let value: &str = rows.rows()[0].try_get("value")?;
- assert_eq!(value, "1");
-
- db.close()?;
- Ok(())
-}
+db.transaction(async |tx| {
+ tx.execute("INSERT INTO notes (body) VALUES ('Async note')").await?;
+ Ok::<_, oliphaunt::Error>(())
+}).await?;
```
-The root handle is exclusive and `Send + !Sync`: ownership may move to another
-thread, but the session cannot be shared concurrently. Keep it in exclusively
-owned application state or on an application-owned database thread. Use
-`oliphaunt::AsyncOliphaunt` when async tasks need a cloneable `Send + Sync`
-handle. Cloned async handles point to the same owner and do not create
-additional PostgreSQL sessions.
-
-
-
+This fragment requires an `AsyncOliphaunt` handle. Keep unrelated network work outside a transaction so it does not hold the database session unnecessarily.
-### Create app data
+## Choose a runtime mode
-Use typed helpers for application queries:
+Direct mode runs in your process. Broker mode moves the database into a helper process:
```rust
-db.execute(
- r#"
- CREATE TABLE IF NOT EXISTS notes (
- id bigserial PRIMARY KEY,
- title text NOT NULL,
- body text NOT NULL,
- created_at timestamptz NOT NULL DEFAULT now()
- )
- "#,
-)?;
-
-db.query_with_params(
- "INSERT INTO notes (title, body) VALUES ($1, $2) RETURNING id::text AS id",
- ["First note", "Stored by embedded PostgreSQL"],
-)?;
-
-let notes = db.query("SELECT id, title FROM notes ORDER BY id DESC LIMIT 20")?;
-let first_title: String = notes.rows()[0].try_get("title")?;
+let mut db = Oliphaunt::builder()
+ .storage(DatabaseStorage::Directory("./app-data/main.oliphaunt".into()))
+ .broker()
+ .open()?;
```
-Expose app-specific commands to a Tauri webview instead of exposing raw database
-handles directly to frontend code.
+For an ORM or connection pool, start a server and keep the returned handle alive:
-
-
-
-### Configure
+```rust
+use oliphaunt::OliphauntServer;
+
+let mut server = OliphauntServer::builder()
+ .storage(DatabaseStorage::Directory("./app-data/server.oliphaunt".into()))
+ .start()?;
+println!("{}", server.connection_string());
+// Connect a PostgreSQL driver here. Close clients before closing server.
+server.close()?;
+```
-Configure storage with `DatabaseStorage`, then select startup identity,
-PostgreSQL startup GUCs, extensions, and database topology through the database
-builder. `Oliphaunt::open()` and `AsyncOliphaunt::open().await` are the default
-direct, SDK-owned temporary-directory terminals. Use
-`.storage(DatabaseStorage::Directory(path))` when data must persist.
+The server lifecycle handle does not run SQL itself. Use `AsyncOliphauntServer` for async server ownership. See [runtime modes](/docs/learn/native-runtime) for failure and concurrency behavior.
-Use `broker_executable` only with `broker().open()`. Local servers have a
-separate `OliphauntServer::builder()` or `AsyncOliphauntServer::builder()` with
-listener/server-executable options and a `start()` terminal. Separate builders
-make cross-topology configuration impossible to express.
+## Select extensions
-
-
+Add the extension crate to `Cargo.toml`:
-### Choose execution placement
+```toml
+oliphaunt-extension-vector = "{{release:oliphaunt-extension-vector}}"
+```
-Use the root import when the caller can intentionally block until each
-operation completes:
+Select it before opening, then enable it with SQL:
```rust
-use oliphaunt::Oliphaunt;
-
-let mut db = Oliphaunt::open()?;
-let rows = db.query("SELECT 42::text AS answer")?;
+let mut db = Oliphaunt::builder()
+ .direct()
+ .extension(oliphaunt_extension_vector::VECTOR)
+ .open()?;
+db.execute("CREATE EXTENSION IF NOT EXISTS vector")?;
```
-Use the asynchronous type when the application executor must stay free:
-
-```rust
-use oliphaunt::AsyncOliphaunt;
+Use the same selection when reopening a database that depends on the extension. See [Extensions](/docs/reference/extensions).
-let db = AsyncOliphaunt::open().await?;
-let rows = db.query("SELECT 42::text AS answer").await?;
-```
+## Back up and restore
-The async API owns its selected runtime on one SDK thread. Calls await fair,
-bounded admission, enter one in-process FIFO, and resolve when that owner
-replies; saturation suspends the future instead of returning a queue-full error.
-This does not make one PostgreSQL session execute queries concurrently.
-
-
-
-
-### Choose a mode
-
-`direct()` runs one serialized embedded session in the process. With the root
-API there is no SDK queue hop; with `AsyncOliphaunt` the SDK calls it from the
-owner thread.
-
-`broker()` talks to a local helper process. Use it for desktop apps that need
-process isolation or several instances managed by one application. A helper
-failure is terminal for that database handle: close it, open a new handle on the
-same persistent directory, and let PostgreSQL recover committed data from WAL.
-Oliphaunt never replaces the helper invisibly or replays an uncertain operation.
-
-`OliphauntServer::builder().start()` (or the async server builder) starts a
-PostgreSQL-compatible server process. The returned lifecycle handle exposes its
-connection string, closed state, and close operation. Use an ordinary driver or
-ORM through that connection string when `psql`, pools, cancellation, SQL, or
-independent client sessions matter.
-
-
-
-
-### Handle lifecycle
-
-Root transactions exclusively borrow the database until commit or rollback,
-and `close()` tears down synchronously. Transaction callbacks return ordinary
-`Result` with `E: From`, so database calls use `?` and
-business-rule failures can remain application-owned. `CallbackAndRollback`
-means rollback was actually sent and failed; `CallbackAndDatabase` means an
-independent database or protocol failure expired the transaction and no
-rollback was sent. Before starting a long root call, obtain `db.cancel_handle()`
-and move that small thread-safe capability to the thread which may interrupt it.
-
-Managed transaction handles deliberately omit raw protocol. Return an error or
-call `rollback()` instead of sending manual transaction-lifecycle SQL.
-Savepoints and `ROLLBACK TO SAVEPOINT` remain valid; manual lifecycle commands
-and `AND CHAIN` are unsupported. If PostgreSQL's response proves that callback
-ownership escaped, the database becomes close-only and the SDK sends no
-speculative `COMMIT` or `ROLLBACK`. A protocol adapter which owns the whole
-lifecycle may instead use raw protocol on the root database handle.
-
-Root transaction callback panics are contained long enough to settle the
-transaction, then resumed when settlement is known. An async transaction-body
-panic unwinds the awaiting task immediately; dropping its active transaction
-queues best-effort rollback in the owner FIFO. That rollback is not promised to
-finish before the unwind reaches the caller, but later database work cannot
-overtake it.
-
-Async work admits and queues fairly on one owner executor. Async `close().await`
-establishes an ordered cutoff: work already in the owner FIFO drains, capacity
-waiters and later application work are rejected, and then the selected runtime
-closes or detaches. A required
-`COMMIT` or `ROLLBACK` remains admissible for a transaction whose `BEGIN`
-crossed the cutoff first. Async `cancel().await` is out of band and does not
-wait behind the SQL FIFO.
-
-Once either placement starts runtime teardown, the handle is terminal even
-when teardown fails: `is_closed()` is true, later work is rejected, and
-repeated close calls return the same retained result. Root/session ownership is
-released only after successful teardown. A failed close intentionally retains
-that ownership until process exit rather than attempting a second destructive
-cleanup.
-
-Raw-stream callbacks return `()` for infallible delivery or `Result<(), E>`
-for a typed parser stop. Root callbacks run inline and may borrow caller state;
-async callbacks run on the owner thread and require `Send + 'static`. A root
-callback panic resumes only after confirmed protocol recovery. A recovered
-async callback panic is `RawStreamError::CallbackPanicked` and leaves the
-session reusable. Independent transport or recovery failure is
-`RawStreamError::Database`, takes precedence, and makes the session close-only.
-
-
-
-
-### Select extensions
-
-Select exact SQL extension names before open. There are no packs, aliases, or
-implicit selectors. If you select `vector`, the generated artifacts include
-`vector` and only its declared dependencies.
-
-
-
-
-### Back up and restore
-
-Use `backup()` and static restore instead of copying PostgreSQL directories from
-application code. Direct and broker expose the one native physical archive;
-restore accepts a new or existing-empty destination. Root backup and restore
-are synchronous. Their `AsyncOliphaunt` counterparts are async and move
-blocking work off the polling executor thread. Server applications use normal
-PostgreSQL tooling.
-
-
-
-
-### Use logical tools
-
-Add the separate `oliphaunt-tools` crate when a server application needs plain
-`pg_dump` or non-interactive `psql`. Pass `server.connection_string()` to the
-tool; the core `oliphaunt` crate does not install or depend on client programs.
+A native backup contains PostgreSQL data and required WAL. Restore into a new or empty root:
```rust
-use oliphaunt_tools::{PgDumpOptions, pg_dump};
-
-let sql = pg_dump(
- server.connection_string(),
- PgDumpOptions::new().arg("--schema-only"),
-)?;
+let archive = db.backup()?;
+db.close()?;
+Oliphaunt::restore("./app-data/restored.oliphaunt", &archive)?;
+let mut restored = Oliphaunt::builder()
+ .storage(DatabaseStorage::Directory("./app-data/restored.oliphaunt".into()))
+ .broker()
+ .open()?;
+restored.close()?;
```
-
-
+The restored handle uses broker mode because direct mode remains bound to its original root for the lifetime of the process, even after close. Reapply required extension selections when opening restored data. Native and WASIX archives are separate families. Server applications use PostgreSQL tools through their endpoint; the optional `oliphaunt-tools` crate supplies `pg_dump` and non-interactive `psql`.
+
+## Cancel and close
+
+Before starting a long synchronous query, obtain `db.cancel_handle()` and pass that cancellation handle to the thread that may interrupt it. The async API exposes `cancel().await`. Cancellation requests do not replace checking the operation's eventual result.
-
+Close explicitly to observe shutdown errors. A failed close leaves the handle terminal; do not retry database work on it. If a broker process dies, close the handle and reopen the persistent root. Check application state before retrying a write with an unknown outcome.
## Troubleshooting
-Check storage ownership errors, missing runtime assets, unsupported-mode errors, extension
-selection errors, and SQLSTATE-bearing PostgreSQL errors. If concurrency looks
-surprising, confirm the selected mode first: direct mode serializes work by
-design, while independent sessions require server mode. If the issue is a
-blocked async executor rather than database topology, confirm the type:
-`oliphaunt::Oliphaunt` blocks its caller and `oliphaunt::AsyncOliphaunt` owns a
-dedicated SDK thread.
-
-## Development resource inputs
-
-The resource separation is unreleased. In the coordinated checkout, direct and
-async builders accept `.seed(NativeClusterSeed)` and
-`.icu_data(NativeResourceDirectory)`. These types are exported by `oliphaunt`:
-applications do not need to install an internal adapter crate to configure them.
-
-Select a Cargo carrier's archive and manifest with
-`NativeClusterSeed::new(archive, manifest)`, or an explicitly unpacked native
-seed directory. The shared native binding validates those inputs before it
-initializes the managed root. Supported desktop opens can initialize without a
-seed; reopening an existing root needs no seed. ICU roots still require ICU data.
-Runtime libraries, seeds, and optional PostgreSQL tools have separate ownership
-and versions. The installation commands above continue to use completed public
-releases, not these unpublished resource candidates.
+| Symptom | Check |
+| --- | --- |
+| Async executor stalls | Use `AsyncOliphaunt` instead of synchronous calls on the executor |
+| Cannot share a synchronous handle | It is not `Sync`; use an exclusive owner or the async handle |
+| PostgreSQL rejects a value | Check SQLSTATE and the parameter/result PostgreSQL type |
+| Root is already owned | Close the existing owner before opening another |
+| Restored data cannot open | Runtime compatibility and required extensions |
diff --git a/src/docs/content/sdk/rust/index.mdx b/src/docs/content/sdk/rust/index.mdx
index 781e5268d..ba5bbe959 100644
--- a/src/docs/content/sdk/rust/index.mdx
+++ b/src/docs/content/sdk/rust/index.mdx
@@ -1,108 +1,71 @@
---
title: Rust SDK
-description: Tauri and native Rust SDK for direct, broker, and server runtime modes.
+description: Run native PostgreSQL in Rust or Tauri with synchronous and asynchronous APIs.
---
-
-
-The Rust SDK targets Tauri apps, native Rust desktop apps, and Rust services
-that want an embedded PostgreSQL runtime with explicit mode selection.
-
-Use this SDK when your application is written in Rust or when a Tauri app keeps
-database ownership in the Rust sidecar. It owns the full native runtime model:
-direct calls for embedded latency, broker helpers for desktop robustness, and
-server mode for normal PostgreSQL clients.
-
-The root `Oliphaunt` type is the synchronous API. Use root
-`AsyncOliphaunt` when the caller needs async methods backed by a dedicated
-owner thread.
+Use `oliphaunt` for native desktop Rust and Tauri applications. Choose [WASIX Rust](/docs/sdk/wasix-rust) when you want to host the WebAssembly runtime instead.
## Install
-Add the crate to your Rust app:
+Use Rust 1.93 or later. Add the crate to `Cargo.toml`:
```toml
[dependencies]
-oliphaunt = "={{release:oliphaunt-rust}}"
-oliphaunt-extension-vector = "={{release:oliphaunt-extension-vector}}"
+oliphaunt = "{{release:oliphaunt-rust}}"
```
-## Open And Query
-
-Then open a database in app-owned storage:
-
-```rust
-use oliphaunt::{DatabaseStorage, Oliphaunt};
+The crate includes the matching native runtime for supported desktop targets. No environment variables or separate runtime download are needed for the default setup.
-fn open_database() -> oliphaunt::Result<()> {
- let mut db = Oliphaunt::builder()
- .storage(DatabaseStorage::Directory("./app-data/main.oliphaunt".into()))
- .direct()
- .extension(oliphaunt_extension_vector::VECTOR)
- .open()?;
+## Run your first query
- let rows = db.query("SELECT 1::text AS value")?;
- assert_eq!(rows.get_text(0, "value")?, Some("1"));
- db.close()?;
- Ok(())
-}
-```
+Create `src/main.rs` with a complete, synchronous example:
-For an async owner-thread handle, only the import and awaiting change:
+
```rust
-use oliphaunt::AsyncOliphaunt;
+use oliphaunt::Oliphaunt;
-async fn open_database() -> oliphaunt::Result<()> {
- let db = AsyncOliphaunt::open().await?;
- let rows = db.query("SELECT 1::text AS value").await?;
- assert_eq!(rows.get_text(0, "value")?, Some("1"));
- db.close().await?;
+fn main() -> Result<(), Box> {
+ let mut db = Oliphaunt::open()?;
+ let result = db.sql("SELECT $1::int4 AS answer").bind(42_i32).query()?;
+ let answer: i32 = result.rows()[0].try_get("answer")?;
+ println!("{answer}"); // 42
+ db.close()?;
Ok(())
}
```
-## Runtime Shape
+Run it with `cargo run`. The default database uses disposable temporary storage. Choose a persistent directory before saving application data.
-Rust exposes the complete native mode model:
+## Keep data between runs
-| Mode | Use it for |
-| --- | --- |
-| Native direct | Lowest-latency embedded PostgreSQL session |
-| Native broker | Helper-process isolation and multi-instance desktop apps |
-| Native server | `psql`, `pg_dump`, ORMs, pools, and independent clients |
+Use this storage configuration instead of the disposable example above. Direct mode stays bound to its first root for the lifetime of the process; closing does not let the same process switch roots.
-Direct and broker mode serialize work through one physical PostgreSQL session.
-Server mode is the mode for independent concurrent PostgreSQL clients.
+Open a stable directory for application data:
+
+```rust
+use oliphaunt::{DatabaseStorage, Oliphaunt};
-Execution placement is orthogonal to those modes:
+let mut db = Oliphaunt::builder()
+ .storage(DatabaseStorage::Directory("./app-data/main.oliphaunt".into()))
+ .direct()
+ .open()?;
+```
-| Import | Calling contract | Ownership |
-| --- | --- | --- |
-| `oliphaunt::Oliphaunt` | Synchronous `&mut self` methods | Exclusive `Send + !Sync` handle; calls block directly until completion |
-| `oliphaunt::AsyncOliphaunt` | Async methods; futures are `Send` when captured inputs, callbacks, and outputs are `Send` | Cloneable `Send + Sync` handle; fair bounded admission and one dedicated owner FIFO |
+Keep the handle in application state. Reopen the same path to access the data again.
-In native direct mode, `liboliphaunt` owns PostgreSQL execution on its backend
-thread. “Synchronous” therefore means that the call blocks until completion,
-not that PostgreSQL is guaranteed to execute on the caller thread.
+## Use an async application
-The selected mode defines support. Use the static runtime support matrix when
-choosing a mode; opened handles expose operations directly.
+Use `AsyncOliphaunt` when queries must not block an async executor:
-## App Responsibilities
+```rust
+use oliphaunt::AsyncOliphaunt;
-- Use an app-owned directory for persistence. Omit storage configuration for an
- SDK-owned temporary directory.
-- Select exact SQL extension names before opening the database.
-- Use SDK backup and restore APIs for data movement instead of copying a live
- PostgreSQL directory.
-- Use `AsyncOliphaunt` when an async executor must remain responsive.
-- Use broker mode for process isolation. Use the dedicated server builder and
- connect an ordinary driver or ORM when independent clients matter.
+let db = AsyncOliphaunt::open().await?;
+let result = db.query("SELECT 42::int4 AS answer").await?;
+db.close().await?;
+```
-## First Query
+The synchronous handle is `Send` but not `Sync`; it requires exclusive access. The async handle is cloneable, `Send`, and `Sync`. Clones share one session and execute work in order.
-Use [Build With Rust](/docs/sdk/rust/guide) for install, open, query,
-configuration, lifecycle, exact extensions, backup, restore, and
-troubleshooting. Use the [API reference](/docs/sdk/rust/api-reference) when you
-need the public type map.
+Continue with the [Rust guide](/docs/sdk/rust/guide), [Tauri integration](/docs/learn/tauri), or [API reference](/docs/sdk/rust/api-reference).
diff --git a/src/docs/content/sdk/swift/api-reference.md b/src/docs/content/sdk/swift/api-reference.md
index a9bbb4cc6..5bdee8d3d 100644
--- a/src/docs/content/sdk/swift/api-reference.md
+++ b/src/docs/content/sdk/swift/api-reference.md
@@ -1,55 +1,56 @@
---
-title: API Reference
-description: Swift SDK API map for Apple app storage, async database calls, lifecycle, and native resources.
+title: Swift API reference
+description: Configuration, typed queries, transactions, and errors in the Swift SDK.
---
-# API Reference
-
-This page maps the Apple
-SDK surface by task.
-
-| Area | Public surface | Use it for |
-| --- | --- | --- |
-| Opening | `OliphauntDatabase.open`, `OliphauntConfiguration`, `OliphauntDatabaseStorage` | Use temporary storage by default or an explicit persistent file URL |
-| Single-statement SQL | `query`, `execute`, `OliphauntQueryResult` | Return ordered raw rows or assert that one extended-query command returns no rows |
-| Multi-statement and metadata | `exec`, `describe` | Return ordered command-or-row results or resolve parameter/result OIDs without executing |
-| Parameters and rows | `OliphauntPostgresOID`, `OliphauntQueryParam`, `OliphauntValueFormat`, `OliphauntQueryRow.value`, `OliphauntPostgresDecodable` | Encode typed/null values and decode by OID-validated index or unambiguous name while retaining `Data` |
-| Raw protocol | database `execProtocolRaw`, `execProtocolRawStream` | Send PostgreSQL protocol bytes as one result or synchronous callback chunks; raw ownership stays outside managed transaction handles, same-handle callback reentry is rejected, confirmed callback recovery leaves the session reusable, and transport/recovery failures poison it |
-| Transactions | `transaction`, transaction `query`/`execute`/`exec`/`describe`, `OliphauntTransaction.rollback`, transaction `isClosed` | Keep typed work on the actor-owned session, return to commit, explicitly roll back without a later commit, and use savepoints for nested work |
-| Lifecycle | database `isClosed`, `cancel`, `close` | FIFO admission drains calls accepted before the close cutoff; cancellation remains available until native teardown starts |
-| Data movement | `backup`, static `restore(destination:bytes:)` | Move user data through the native physical archive |
-| Diagnostics | result `notices`, `OliphauntError`, `OliphauntPostgresError`, `OliphauntTransactionRollbackError`, `OliphauntTransactionDatabaseError` | Preserve PostgreSQL diagnostics and independent transaction failures without dropping the callback error |
-
-```swift
-let result = try await database.query(
- "SELECT $1::int4 AS answer",
- parameters: [.int32(41)]
-)
-let answer: Int32? = try result.rows[0].value(named: "answer")
-```
-
-The cross-SDK behavior follows the
-[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md).
-
-Managed transaction callbacks must not issue outer-lifecycle SQL: `BEGIN`/`START
-TRANSACTION`, `COMMIT`/`END`, a full `ROLLBACK`/`ABORT` (with or without `AND
-[NO] CHAIN`), or `PREPARE TRANSACTION`. Use
-`rollback()` or return from the callback for outer settlement; `SAVEPOINT`,
-`RELEASE SAVEPOINT`, and `ROLLBACK TO SAVEPOINT` remain supported SQL. PostgreSQL
-reports `ROLLBACK TO` and `ROLLBACK AND CHAIN` with the same `ROLLBACK` command
-tag and transactional ready status, so the SDK rejects `ROLLBACK`/`ABORT ...
-AND CHAIN` before dispatch and still validates every actual protocol boundary.
-If the callback catches a poisoning database or rollback error and returns, the
-transaction still fails with the stored original error.
-
-After automatic rollback succeeds, the original callback error is rethrown.
-`OliphauntTransactionRollbackError` reports a callback-plus-rollback failure in
-its public `callbackError` and `rollbackError` fields. If the callback throws a
-different error after an earlier independent database or protocol failure
-poisoned or expired ownership, `OliphauntTransactionDatabaseError` reports both
-through its public `callbackError` and `databaseError` fields, and the database
-is close-only. Ordinary PostgreSQL statement errors that remain safely
-rollbackable do not automatically create either composite error.
-
-iOS and macOS apps start with `OliphauntDatabase`. The C ABI remains the
-lower-level boundary used by the Swift package.
+Import `Oliphaunt`. `OliphauntDatabase` is an actor exposing `async throws` database operations.
+
+## Open and restore
+
+`OliphauntDatabase.open(configuration:)` returns a database. The configuration defaults to `OliphauntConfiguration()`.
+
+| Configuration field | Type / default |
+| --- | --- |
+| `storage` | `OliphauntDatabaseStorage`; `.temporaryDirectory` |
+| Persistent storage | `.directory(URL)` using a file URL, or `.applicationData(name:)` |
+| `startupGUCs` | `[OliphauntStartupGUC]`; empty |
+| `username`, `database` | Optional strings; fresh roots use `postgres` |
+| `extensions` | `[OliphauntExtension]`; empty, typed extension selections |
+
+Construct a startup setting with `OliphauntStartupGUC("name", "value")`. Identity fields select an existing role and database.
+
+`OliphauntDatabase.restore(destination:bytes:)` accepts a destination `URL` and archive `Data`. It restores into new or empty persistent storage.
+
+## Broker mode
+
+`OliphauntBroker.open(configuration:options:)` returns the same database interface from a separate process. Use application-data names for persistent broker storage. See [mobile broker setup](/docs/learn/mobile-stability#broker-mode) for platform requirements, file-based restore, deadlines, and failure handling.
+
+## Queries
+
+| Operation | Purpose |
+| --- | --- |
+| `query(_:parameters:)` | Buffered typed rows |
+| `execute(_:parameters:)` | Command result |
+| `exec(_:)` | Results for a multi-statement SQL script |
+| `describe(...)` | Statement parameter and column metadata |
+| `transaction(_:)` | Exclusive callback transaction |
+
+Query parameters include typed values such as `.string`, `.int32`, and `.int64`. Read a column through `result.rows[index].value(named:)` with an explicit compatible Swift type. Use optional types for nullable columns.
+
+Transaction callbacks receive an `OliphauntTransaction` with typed query methods and `rollback()`. The handle expires when the transaction settles. Returning commits; throwing rolls back. Savepoints are allowed; manually ending or replacing the outer transaction is unsupported.
+
+## Lifecycle and raw protocol
+
+`backup()` returns `Data`. `cancel()` requests an interrupt. `close()` observes shutdown; `isClosed` reports terminal state. Work is serialized on one PostgreSQL session, away from the main actor.
+
+Buffered `execProtocolRaw` and callback `execProtocolRawStream` are database-only interfaces for protocol integrations. Stream callbacks are synchronous backpressure boundaries. Do not re-enter database or transaction operations from a callback, apart from the documented out-of-band cancellation path.
+
+## Errors
+
+PostgreSQL errors retain backend diagnostics and SQLSTATE. Runtime, storage, protocol, and lifecycle failures are distinct from ordinary SQL failures.
+
+`OliphauntTransactionRollbackError` retains `callbackError` and `rollbackError`. `OliphauntTransactionDatabaseError` retains `callbackError` and `databaseError` when an independent database failure already invalidated the transaction. A database with uncertain protocol state becomes close-only.
+
+Swift task cancellation alone does not cancel a PostgreSQL query. Call the explicit cancellation API and observe the query result.
+
+See the [Swift guide](/docs/sdk/swift/guide) for application recipes and extension packaging.
diff --git a/src/docs/content/sdk/swift/guide.mdx b/src/docs/content/sdk/swift/guide.mdx
index f2a49b88d..73b40bcdc 100644
--- a/src/docs/content/sdk/swift/guide.mdx
+++ b/src/docs/content/sdk/swift/guide.mdx
@@ -1,209 +1,116 @@
---
-title: Build With Swift
-description: Add Oliphaunt to iOS or macOS with Swift concurrency, app-container storage, exact extensions, backup, and app-owned lifecycle actions.
+title: Swift guide
+description: Query data, manage transactions, select extensions, and restore backups in Apple apps.
---
-# Build With Swift
+These recipes use an open `db` from the [Swift quickstart](/docs/sdk/swift). Import `Oliphaunt` and call database methods from an async context.
-Use the Swift SDK in iOS and macOS apps. It wraps the native runtime behind
-Swift async APIs and keeps database work off the main actor.
+## Query application data
-
-React Native on Apple platforms delegates runtime behavior through this SDK, but
-Swift and SwiftUI apps use `OliphauntDatabase` directly.
-
-
-
-
-
-
+```swift
+try await db.execute("""
+CREATE TABLE IF NOT EXISTS notes (
+ id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ body text NOT NULL
+)
+""")
+let inserted = try await db.query(
+ "INSERT INTO notes (body) VALUES ($1) RETURNING id",
+ parameters: [.string("First note")]
+)
+let id: Int64? = try inserted.rows[0].value(named: "id")
+```
-### Install
+Parameters bind values without SQL interpolation. Decode a result using a Swift type compatible with its PostgreSQL column type. SQL null becomes an optional value.
-Add the Swift package in Xcode or `Package.swift`. The package includes the
-Swift API plus the platform runtime artifacts required for the selected target.
+## Run a transaction
```swift
-dependencies: [
- .package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "{{release:oliphaunt-swift}}")
-]
+try await db.transaction { tx in
+ try await tx.execute(
+ "INSERT INTO notes (body) VALUES ($1)",
+ parameters: [.string("First")]
+ )
+ try await tx.execute(
+ "INSERT INTO notes (body) VALUES ($1)",
+ parameters: [.string("Second")]
+ )
+}
```
-Persistent storage lives under your app container. App users install your app; the
-SDK package carries the runtime files it needs.
+Returning commits and throwing rolls back. Use `tx` for every statement in the callback. Do not call the outer database or issue manual transaction-lifecycle commands. Use `tx.rollback()` for explicit rollback; savepoints are supported.
+
+## Choose process isolation
-
-
+The quickstart uses direct mode. For a separate database process, follow [mobile broker setup](/docs/learn/mobile-stability#broker-mode). Broker mode requires its own storage and restore path; use the recipes below for direct mode.
-### Open and query
+## Back up and restore
-This example selects the generated vector resource product described in the Swift SDK README.
+Direct mode stays bound to one database root and configuration for the lifetime of the application process. Closing a handle does not let that process switch to another root. Prepare the restored data, then use it on the next launch.
-Open an `OliphauntDatabase` with a persistent file URL, run SQL with async calls, and
-close when the app no longer needs the handle.
+Use archive bytes for export, not a live directory copy:
```swift
-import OliphauntExtensionVector
+let archive = try await db.backup()
+try await db.close()
+try await OliphauntDatabase.restore(destination: restoredURL, bytes: archive)
+```
-let appSupport = FileManager.default.urls(
- for: .applicationSupportDirectory,
- in: .userDomainMask
-)[0]
+On a subsequent application launch, open the restored destination:
-let database = try await OliphauntDatabase.open(
- configuration: OliphauntConfiguration(
- storage: .directory(appSupport.appending(path: "main.oliphaunt")),
- extensions: [OliphauntExtensionVector.resource]
- )
+```swift
+let restored = try await OliphauntDatabase.open(
+ configuration: OliphauntConfiguration(storage: .directory(restoredURL))
)
+try await restored.close()
+```
-let rows = try await database.query("SELECT 1::text AS value")
-let value: String? = try rows.rows[0].value(named: "value")
+Here `restoredURL` is an app-owned file URL for a new or empty directory. Restore rejects nonempty destinations. Reapply the original database's required extension selection when reopening. Physical backups require a compatible native runtime.
-try await database.close()
-```
+## Add an extension
-Keep one database handle in app state and share it through your app's dependency
-model. The handle owns a serialized session boundary.
+The base Swift package is extension-free. Add the generated product to your application before selecting it at open.
-
-
+1. Install [Bun](https://bun.sh/docs/installation), then obtain the Swift extension generator from the Oliphaunt source package matching your Swift dependency.
+2. Download the matching `vector` Swift extension carrier JSON from its [release](https://github.com/f0rr0/oliphaunt/releases/tag/oliphaunt-extension-vector-v{{release:oliphaunt-extension-vector}}).
+3. Generate a local Swift package with the command below, replacing the two input paths.
-### Create app data
+```sh
+bun /path/to/oliphaunt/src/native/sdks/swift/tools/render-extension-products.mts \
+ --extension-carrier /path/to/oliphaunt-extension-vector-{{release:oliphaunt-extension-vector}}-swift-extension-carrier.json \
+ --extensions vector \
+ --output-dir ./OliphauntExtensions
+```
-Use async SQL helpers for application data. A SwiftUI model or app service can
-own the database handle and expose app-specific methods:
+The output directory must not already exist. Add it to Xcode as a local package and link the generated `OliphauntExtensionVector` product to your app. Select its resource when opening:
```swift
-try await database.execute("""
-CREATE TABLE IF NOT EXISTS notes (
- id bigserial PRIMARY KEY,
- title text NOT NULL,
- body text NOT NULL,
- created_at timestamptz NOT NULL DEFAULT now()
-)
-""")
-
-try await database.query(
- "INSERT INTO notes (title, body) VALUES ($1, $2) RETURNING id::text AS id",
- parameters: [
- .string("First note"),
- .string("Stored by embedded PostgreSQL")
- ]
-)
+import OliphauntExtensionVector
-let notes = try await database.query(
- "SELECT id, title FROM notes ORDER BY id DESC LIMIT 20"
+let db = try await OliphauntDatabase.open(
+ configuration: OliphauntConfiguration(extensions: [OliphauntExtensionVector.resource])
)
-let firstTitle: String? = try notes.rows[0].value(named: "title")
+try await db.execute("CREATE EXTENSION IF NOT EXISTS vector")
```
-Keep UI updates on the main actor, but keep database work behind the SDK's async
-database actor.
-
-
-
-
-### Configure
-
-Configure storage, selected exact extensions, startup identity, and PostgreSQL
-startup GUCs through the Swift configuration API. Storage defaults to
-`.temporaryDirectory`; choose `.directory(url)` for persistence. Advanced
-resource overrides allow app-owned resources. Released versions retain their
-packaged defaults; the development resource selection is described below.
-
-
-
-
-### Choose a mode
-
-Native direct is the Apple runtime. It uses one resident backend per app process
-and one physical session.
-
-
-
-
-### Handle lifecycle
-
-Swift exposes lifecycle as `async throws`. A dedicated serial owner queue runs
-storage preparation, open, SQL/protocol work, backup, and close away from the
-main actor. Ordinary work, transaction controls, and close share FIFO admission.
-A transaction or close is an atomic cutoff: calls admitted earlier drain before
-it, and incompatible later calls fail. `cancel()` uses a separate control queue
-so it can interrupt the active owner call. It remains available while close
-drains earlier admissions and stops when native teardown starts. Raw-stream
-callbacks are synchronous backpressure boundaries: same-handle database and
-transaction work is rejected from their scope, except for out-of-band
-`cancel()`. A callback failure is returned only after confirmed protocol
-recovery and leaves the session reusable. A raw buffered or streaming
-transport/recovery failure poisons the database. Task cancellation alone does not
-interrupt PostgreSQL; use `cancel()` and `close()` explicitly when app lifecycle
-policy requires them. Run `execute("CHECKPOINT")` only when an explicit
-PostgreSQL checkpoint is needed.
-
-Inside `transaction {}`, use the transaction's typed `query`, `execute`, `exec`,
-and `describe` methods. Return to commit or call `rollback()` to settle the outer
-transaction; do not issue outer-lifecycle SQL such as `BEGIN`/`START TRANSACTION`,
-`COMMIT`/`END`, a full `ROLLBACK`/`ABORT` (with or without `AND [NO] CHAIN`), or
-`PREPARE TRANSACTION`. Nested `SAVEPOINT`, `RELEASE
-SAVEPOINT`, and `ROLLBACK TO SAVEPOINT` SQL is supported. PostgreSQL exposes
-`ROLLBACK TO` and `ROLLBACK AND CHAIN` with the same `ROLLBACK` command tag and
-transactional ready status, so the SDK rejects `ROLLBACK`/`ABORT ... AND CHAIN`
-before dispatch and still validates every actual protocol boundary. Raw
-protocol APIs stay on the database for callers that explicitly own transaction
-lifecycle.
-
-After automatic rollback succeeds, Swift rethrows the original callback error.
-If the callback catches a poisoning database or rollback error and returns, the
-transaction still fails with that stored original error.
-If rollback also fails, `OliphauntTransactionRollbackError.callbackError` and
-`.rollbackError` preserve both outcomes. If the callback throws a different
-error after an earlier independent database or protocol failure poisoned or
-expired transaction ownership, `OliphauntTransactionDatabaseError.callbackError`
-and `.databaseError` preserve both and the database is close-only. An ordinary
-PostgreSQL statement error that remains safely rollbackable is not automatically
-wrapped in either composite error.
-
-
-
-
-### Select extensions
-
-Select exact SQL extension names in app configuration. The app bundle contains
-selected extension artifacts plus required dependencies. `CREATE EXTENSION`
-succeeds when the selected runtime resources contain that extension for the
-Apple target.
-
-
-
-
-### Back up and restore
-
-Use `backup()` and static `restore(destination:bytes:)` with app-owned file
-URLs. Restore accepts a new or existing-empty destination and rejects nonempty
-data without mutation.
-
-
-
-
-
+For multiple extensions, supply each required carrier with another `--extension-carrier` option and list the SQL names in `--extensions`. The generated package includes their required dependencies. Check the [catalog](/docs/reference/extension-catalog) before selecting an extension.
-## Troubleshooting
+Applications that need ICU collations also link the `OliphauntICU` SwiftPM product. Choose the ICU seed when creating a new iOS database that uses ICU collations.
-Most Apple failures come from invalid file URLs, missing runtime resources, storage
-locks, runtime errors, or extension selection mismatches. PostgreSQL
-errors preserve SQLSTATE where the backend returns it.
+## Cancel and close
-## Development resource packaging
+Cancelling a Swift task alone does not interrupt PostgreSQL. Use `try await db.cancel()` to request interruption, then await and handle the database operation's outcome.
-These resource-package changes are unreleased. The published installation
-versions above do not include this new package arrangement; use a coordinated
-checkout for this section.
+Close explicitly with `try await db.close()`. Close rejects new work and drains earlier accepted work. A shutdown failure leaves the handle terminal. Keep UI updates on the main actor and let the SDK run database work on its owner queue.
+
+A transaction callback error is rethrown after successful rollback. If rollback or independent database recovery also fails, the SDK exposes both causes; see [errors](/docs/sdk/swift/api-reference#errors).
+
+## Troubleshooting
-Select `OliphauntSeedNativeIOSStandard` or `OliphauntSeedNativeIOSICU` from the
-independent database-resources Swift source package for a new iOS database. The
-ICU product depends on `OliphauntICU`; an existing ICU database still needs that
-data even when the seed is omitted. The SDK discovers the selected bundles.
-The resource archive can be added as a local Swift package; no separate remote
-Swift repository URL has been published. Device qualification of the new seed
-carriers remains pending.
+| Symptom | Check |
+| --- | --- |
+| Invalid storage URL | Use an app-owned file URL, not a remote URL |
+| Missing extension | Link and register its generated Swift product before open |
+| Missing runtime resources | The app target links `Oliphaunt` and includes its resolved framework |
+| Root already in use | Keep one owner and close it before reopening |
+| Background writes are interrupted | Keep transactions short and follow [mobile lifecycle guidance](/docs/learn/mobile-stability) |
diff --git a/src/docs/content/sdk/swift/index.mdx b/src/docs/content/sdk/swift/index.mdx
index 2d72d7cd2..8b88de488 100644
--- a/src/docs/content/sdk/swift/index.mdx
+++ b/src/docs/content/sdk/swift/index.mdx
@@ -1,73 +1,73 @@
---
title: Swift SDK
-description: Apple SDK for iOS and macOS apps using Swift concurrency.
+description: Add embedded PostgreSQL to an iOS or macOS app with Swift concurrency.
---
-
-
-The Swift SDK is the Apple SDK for iOS and macOS apps. It wraps the native
-runtime with Swift concurrency, app-container storage defaults, resource bundle
-handling, and platform lifecycle APIs.
-
-Use this SDK directly in SwiftUI, UIKit, AppKit, and app extension-safe code
-where supported. React Native on Apple platforms delegates runtime work through
-this SDK, so the Swift lifecycle model is the Apple behavior source.
+Use `Oliphaunt` from Swift or SwiftUI on iOS 17+ and macOS 14+. The package uses Swift 6 and includes the native runtime through Swift Package Manager.
## Install
-Add the Swift package from Xcode or `Package.swift`:
+In Xcode, add `https://github.com/f0rr0/oliphaunt.git` as a package dependency and select version **{{release:oliphaunt-swift}}**. Add the `Oliphaunt` product to your app target.
+
+For a Swift package, add this dependency to `Package.swift`:
```swift
.package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "{{release:oliphaunt-swift}}")
```
-The package carries the Swift API and the native runtime artifacts for supported
-Apple targets.
+Then add `.product(name: "Oliphaunt", package: "oliphaunt")` to your target's dependencies. For a new iOS database, also download `database-resources-{{release:database-resources}}-swift.zip` from the [database resources release](https://github.com/f0rr0/oliphaunt/releases/tag/database-resources-v{{release:database-resources}}). Extract it, add the directory as a local Swift package, and link `OliphauntSeedNativeIOSStandard` to the app target. This supplies the initial empty database; it is required on iOS. macOS can initialize a new database without a seed.
+
+For ICU collations, choose `OliphauntSeedNativeIOSICU` instead; it includes `OliphauntICU`. Keep ICU data linked when reopening an ICU database.
-## Open And Query
+## Run your first query
-Open a database from an async context after adding the generated vector resource product:
+Call this function from an async context, such as a SwiftUI `.task`. It uses disposable storage and closes after reading a parameterized query result.
+
+
```swift
import Oliphaunt
-import OliphauntExtensionVector
-
-let appSupport = FileManager.default.urls(
- for: .applicationSupportDirectory,
- in: .userDomainMask
-)[0]
-
-let database = try await OliphauntDatabase.open(
- configuration: OliphauntConfiguration(
- storage: .directory(appSupport.appending(path: "main.oliphaunt")),
- extensions: [OliphauntExtensionVector.resource]
- )
-)
-let rows = try await database.query("SELECT 1::text AS value")
-try await database.close()
+func firstQuery() async throws {
+ let db = try await OliphauntDatabase.open()
+ do {
+ let result = try await db.query(
+ "SELECT $1::int4 AS answer",
+ parameters: [.int32(42)]
+ )
+ let answer: Int32? = try result.rows[0].value(named: "answer")
+ print(answer ?? 0) // 42
+ } catch {
+ try? await db.close()
+ throw error
+ }
+ try await db.close()
+}
```
-## Runtime Shape
+Database work runs off the main actor. The database actor coordinates one PostgreSQL session; concurrent tasks do not create additional sessions.
+
+## Keep data between launches
-Swift is async-first and actor-owned. Direct mode owns one resident backend per
-app process and one serialized physical session.
+Use this storage configuration instead of the disposable example above. Direct mode stays bound to its first root for the lifetime of the process; closing does not let the same process switch roots.
-The actor boundary keeps database calls off the main actor. App code can issue
-concurrent Swift tasks against the same database handle; direct mode queues them
-against the resident backend and preserves transaction ordering.
+Use a file URL in your application's container:
-## App Responsibilities
+```swift
+import Foundation
-- Use `.directory(url)` for persistent user data. Omit it for SDK-owned
- temporary storage.
-- Select exact SQL extension names so the app bundle contains only selected
- extension artifacts and declared dependencies.
-- Use backup and restore APIs for export, import, and user-visible data
- movement.
+let directory = try FileManager.default.url(
+ for: .applicationSupportDirectory,
+ in: .userDomainMask,
+ appropriateFor: nil,
+ create: true
+).appending(path: "main.oliphaunt")
+
+let db = try await OliphauntDatabase.open(
+ configuration: OliphauntConfiguration(storage: .directory(directory))
+)
+```
-## First Query
+Keep the handle in an application service. Reopen the same directory to access saved data. The default `.temporaryDirectory` is disposable.
-Use [Build With Swift](/docs/sdk/swift/guide) for open/query, app lifecycle,
-extension selection, and backup/restore. Use the
-[API reference](/docs/sdk/swift/api-reference) for the public API map.
+Continue with the [Swift guide](/docs/sdk/swift/guide), [mobile lifecycle guide](/docs/learn/mobile-stability), or [API reference](/docs/sdk/swift/api-reference).
diff --git a/src/docs/content/sdk/typescript/api-reference.md b/src/docs/content/sdk/typescript/api-reference.md
index 9fcb52f69..4a8691d54 100644
--- a/src/docs/content/sdk/typescript/api-reference.md
+++ b/src/docs/content/sdk/typescript/api-reference.md
@@ -1,80 +1,64 @@
---
-title: TypeScript API Reference
-description: TypeScript API map for desktop JavaScript, native engines, SQL, lifecycle, and data movement.
+title: TypeScript API reference
+description: Entry points, configuration, query results, errors, and lifecycle for @oliphaunt/ts.
---
-# TypeScript API Reference
+Import `Oliphaunt` from `@oliphaunt/ts`. The package exports TypeScript declarations for the API below.
-This page maps native
-`@oliphaunt/ts` by task; WASIX TypeScript is documented separately.
+## Entry points
-| Area | Public surface | Use it for |
+| Method | Returns | Behavior |
| --- | --- | --- |
-| Opening | `Oliphaunt.open`, `OpenConfig`, `DatabaseStorage` | Open with temporary storage by default or an explicit persistent directory |
-| Topology | `topology` | Use the direct topology (the default) or select the broker topology |
-| Server | `Oliphaunt.openServer`, server `connectionString`, `closed`, `close`, `Symbol.asyncDispose` | Own a PostgreSQL listener and connect caller-owned ORMs, drivers, or tools; the handle has no privileged database connection |
-| Single-statement SQL | decoded `query`, byte-preserving `queryRaw`, `execute` | Read object or array rows by default, retain exact wire rows when needed, or assert a command returns no rows |
-| Multi-statement and metadata | `exec`, `describe` | Return simple-query results in statement order or resolve parameter/result OIDs without executing |
-| Parameters and codecs | `text`, `binary`, `typedNull`, `json`, `array`, `postgresOids`, per-query encoders and decoders | Use safe scalar inference, deterministic PostgreSQL types, or extension-owned OID codecs |
-| Transactions | callback `transaction`, transaction `rollback`, transaction `closed` | Own the physical session for a callback and explicitly roll back without a later commit |
-| Raw protocol | database `execProtocolRaw`, `execProtocolRawStream` | Send PostgreSQL protocol bytes as one owned response or synchronous callback chunks through the selected native path; transaction and server handles do not expose this bypass |
-| Data movement | `backup`, `restore`, `RestoreOptions` | Move the native physical archive to a new or empty destination |
-| Optional tools | `pgDump`, `psql`, `PostgresToolError` from `@oliphaunt/tools` | Run standard logical tools against a native server connection string without adding tools to the core SDK |
-| Lifecycle | read-only `closed`, `cancel`, `close`, `Symbol.asyncDispose` | Explicitly await cleanup and coordinate active work without a separate readiness API |
-| Diagnostics | query-scoped `notices`, `PostgresError` | Preserve ordered PostgreSQL notices and SQLSTATE-bearing error fields |
-
-```ts
-const result = await db.query('SELECT $1::int4 AS answer', [41]);
-const answer = result.rows[0]?.answer;
-const description = await db.describe('SELECT $1::uuid', [2950]);
-```
-
-The cross-SDK behavior follows the
-[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md).
-
-Inside a callback transaction, do not issue manual `BEGIN`, `START
-TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`.
-Use callback return/throw or `rollback()`; `SAVEPOINT` and `ROLLBACK TO` are
-supported. `ROLLBACK AND CHAIN` is unsupported and wire-indistinguishable from
-`ROLLBACK TO`, so Oliphaunt rejects `ROLLBACK`/`ABORT ... AND CHAIN` before
-dispatch and enforces every other ownership boundary from PostgreSQL response
-frames. A proven escape makes the database close-only and suppresses any
-follow-up SDK transaction command.
-
-After a callback failure, a successful automatic rollback rethrows the original
-value unchanged. A simultaneous rollback failure produces an `AggregateError`
-with the callback failure first and rollback failure second. If an earlier
-independent database or protocol failure already poisoned or expired ownership
-and the callback throws a different value, an `AggregateError` retains the
-callback failure first and database failure second, and the database is
-close-only. Ordinary PostgreSQL statement errors that remain safely rollbackable
-do not automatically produce an aggregate.
-
-The root package is the only native runtime entrypoint. It detects Node.js,
-Bun, or Deno and resolves the matching installed runtime internally; native
-binding factories, runtime handles, and runtime-specific package subpaths are
-not consumer APIs.
-
-React Native apps use `@oliphaunt/react-native`. This package is for desktop
-JavaScript runtimes over the native runtime family. Browser applications use
-[`@oliphaunt/wasix-ts`](/docs/sdk/wasix-typescript).
-
-`close()` and `Symbol.asyncDispose` are the public lifecycle contract. A
-forgotten direct, broker, or server object has a best-effort runtime fallback,
-but garbage collection is neither prompt nor observable. On Deno the fallback schedules
-nonblocking, generation-guarded terminal cleanup: a stale finalizer cannot
-close a newer logical lease, and an executed cleanup spends the native database
-process lifetime. Broker/server fallbacks schedule cleanup using only an exact
-private handle plus a lease generation; stale generations are no-ops. Always
-close explicitly when the process must reuse the resident runtime or report
-teardown failure.
-
-Native direct close remains retryable only when logical deactivation did not
-occur. A broker/server teardown error past its destructive cutoff is terminal:
-`closed` is true, later work is rejected, and repeated close calls return the
-same attempt outcome. Raw-stream callbacks are synchronous and cannot reenter
-same-handle work other than out-of-band cancellation. After `close()` stops
-ordinary admission, cancellation remains available until runtime teardown starts.
-A thrown callback is returned unchanged only when the runtime confirms recovery
-to a known PostgreSQL protocol boundary. An execution, transport, or recovery
-failure takes precedence and poisons a session whose state is unknown.
+| `Oliphaunt.open(config?)` | `Promise` | Opens a direct or broker query session |
+| `Oliphaunt.openServer(config?)` | `Promise` | Starts a local PostgreSQL server |
+| `Oliphaunt.restore(storage, bytes, options?)` | `Promise` | Restores a native archive into a new or empty directory |
+
+## Open configuration
+
+| Option | Type / default | Meaning |
+| --- | --- | --- |
+| `storage` | `DatabaseStorage`; temporary directory | `{ kind: 'directory', path: string }` persists data |
+| `topology` | `'direct'` or `'broker'`; direct | Execution mode |
+| `extensions` | `readonly NativeExtension[]`; empty | Imported extension descriptors |
+| `seed`, `icuData` | Optional `NativeResourceDirectory` | Initialization seed or ICU resources |
+| `startupGUCs` | `Record` | PostgreSQL settings applied at startup |
+| `username`, `database` | Optional strings | Existing PostgreSQL identity; fresh roots use `postgres` |
+| `libraryPath`, `runtimeDirectory` | Optional strings | Advanced native resource overrides |
+| `brokerExecutable` | Optional string | Broker executable override |
+
+Restore accepts `{ kind: 'directory', path: string }`.
+
+Server configuration replaces `topology`, `brokerExecutable`, `libraryPath`, and `seed` with `serverExecutable` and `listen`. TCP listen accepts an optional port; Unix listen requires a socket directory and accepts a port.
+
+## Query methods
+
+| Method | Result |
+| --- | --- |
+| `query(sql, parameters?, options?)` | Decoded `QueryResult` with `rows` and field metadata |
+| `execute(sql, parameters?, options?)` | `CommandResult` with command metadata |
+| `queryRaw(sql, parameters?, options?)` | Raw column values and field metadata |
+| `exec(sql, options?)` | Results for a multi-statement SQL script |
+| `describe(sql, parameterTypeOids?)` | Parameter and result-field descriptions |
+| `transaction(body)` | The callback's returned value, after commit |
+
+Parameters are positional values corresponding to `$1`, `$2`, and so on. Explicit SQL casts make ambiguous parameters predictable. Generic row annotations describe your expected shape; they do not validate a SQL schema at runtime. Query options support custom type parsers and encoders.
+
+## Database lifecycle
+
+`backup()` returns `Promise`. `cancel()` requests interruption of active work. `close()` returns `Promise` and `closed` reports terminal state. The handle also implements `Symbol.asyncDispose` for `await using` in runtimes that support it.
+
+The transaction object exposes the typed query methods and `rollback()`. It expires when the callback settles and cannot escape into later application work. It has no raw-protocol or backup methods.
+
+The server handle exposes `connectionString`, `closed`, `close()`, and `Symbol.asyncDispose`. SQL, cancellation, and backup through a server use your PostgreSQL driver or tools.
+
+## Raw protocol
+
+`execProtocolRaw(input)` returns a buffered PostgreSQL protocol response. `execProtocolRawStream(input, onChunk)` delivers `Uint8Array` chunks to a synchronous callback that returns `undefined`. Input accepts supported binary buffers or byte arrays.
+
+A stream callback is a backpressure boundary. Do not run queries or close the same handle from it. Raw protocol callers own protocol framing and transaction lifecycle. A transport/recovery failure can make the handle close-only even if callback delivery stopped earlier.
+
+## Errors
+
+`PostgresError` preserves backend fields including `sqlstate`. Other errors cover loading, storage, lifecycle, and protocol failures. Composite transaction failures preserve both the callback error and the database/rollback failure. Inspect the original causes rather than retrying based only on a message string.
+
+See the [TypeScript guide](/docs/sdk/typescript/guide) for complete recipes.
diff --git a/src/docs/content/sdk/typescript/guide.mdx b/src/docs/content/sdk/typescript/guide.mdx
index 18a1bd075..a4a9ef6f7 100644
--- a/src/docs/content/sdk/typescript/guide.mdx
+++ b/src/docs/content/sdk/typescript/guide.mdx
@@ -1,242 +1,129 @@
---
-title: Build With TypeScript
-description: Use the native desktop JavaScript SDK in Node.js, Bun, or Deno with native engines and selected extensions.
+title: TypeScript guide
+description: Use parameters, transactions, persistent storage, extensions, and backups in native JavaScript apps.
---
-# Build With TypeScript
+These recipes use an open `db` from the [TypeScript quickstart](/docs/sdk/typescript). Keep one handle in your application service and close it during shutdown.
-Use `@oliphaunt/ts` in Node.js, Bun, and Deno. It provides a JavaScript API over
-native Oliphaunt runtime assets and native engines where supported.
+## Query application data
-
-Use this package for Node.js, Bun, and Deno. Tauri apps currently keep the
-database in Rust state behind narrow app-owned commands. React Native apps use
-the React Native SDK because
-mobile runtime work flows through Swift and Kotlin.
+Create the table before running the insert and read:
-Browser applications use the separate
-[`@oliphaunt/wasix-ts`](/docs/sdk/wasix-typescript) package. This native
-package does not fall back to WASIX, and the WASIX package does not fall back to
-native execution.
-
+```ts
+await db.execute(`
+ CREATE TABLE IF NOT EXISTS notes (
+ id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ body text NOT NULL
+ )
+`);
-Database methods are promise-based on all three runtimes. PostgreSQL open,
-query, backup, restore, and close work uses addon jobs on Node/Bun or Deno
-nonblocking FFI, so it does not execute on the JavaScript event loop. Native
-module loading itself remains a synchronous one-time platform step
-(`require()` on Node/Bun and `dlopen()` on Deno); it is not a separate blocking
-database API.
+const inserted = await db.query(
+ 'INSERT INTO notes (body) VALUES ($1) RETURNING id',
+ ['First note'],
+);
+const notes = await db.query('SELECT id, body FROM notes ORDER BY id');
+console.log(notes.rows);
+```
+
+Use parameters for values; do not interpolate user input into SQL. Use `query` when you need rows, `execute` when you need command metadata, and `exec` for a trusted SQL script containing multiple statements.
-Deno's nonblocking calls carry a native error-capture buffer with each Promise.
-The worker fills that buffer before returning, so concurrent failures cannot be
-misreported through a later thread-local or shared-handle error lookup.
+## Run a transaction
-
+Use the callback's `tx` object for every statement in the transaction:
-
-
+```ts
+await db.transaction(async (tx) => {
+ await tx.execute('INSERT INTO notes (body) VALUES ($1)', ['First']);
+ await tx.execute('INSERT INTO notes (body) VALUES ($1)', ['Second']);
+});
+```
-### Install
+Returning commits; throwing rolls back. The callback's return value becomes the transaction result. Do not call the outer `db` or send manual `BEGIN`, `COMMIT`, or full `ROLLBACK` commands inside the callback. Use `tx.rollback()` for an explicit rollback. Savepoints are supported.
-Install the npm package. Runtime assets and helper executables resolve through
-package configuration.
+## Select extensions
+
+Install the native extension package and import its descriptor:
```sh
-npm install @oliphaunt/ts@{{release:oliphaunt-js}} @oliphaunt/extension-vector
+npm install @oliphaunt/extension-vector@{{release:oliphaunt-extension-vector}}
```
-
-
-
-### Open and query
+```ts
+import vector from '@oliphaunt/extension-vector';
-Open the package client, choose persistent storage, run SQL, and close the
-database.
+const db = await Oliphaunt.open({ extensions: [vector] });
+await db.execute('CREATE EXTENSION IF NOT EXISTS vector');
+```
-```ts
-import { Oliphaunt } from '@oliphaunt/ts';
-import { vector } from '@oliphaunt/extension-vector';
+The extension must match the native runtime and target platform. See [Extensions](/docs/reference/extensions) for the selection rules and catalog.
-const db = await Oliphaunt.open({
- storage: { kind: 'directory', path: './app-data/main.oliphaunt' },
- extensions: [vector],
-});
+## Back up and restore
-const rows = await db.query('SELECT 1::text AS value');
-const value = rows.rows[0]?.value;
+`backup()` returns a physical archive as a `Uint8Array`. Save or transfer those bytes using your host's file APIs. Restore to a new or empty directory:
+```ts
+const archive = await db.backup();
await db.close();
-```
+await Oliphaunt.restore(
+ { kind: 'directory', path: './app-data/restored.oliphaunt' },
+ archive,
+);
-Keep one client per database instance unless you intentionally use a mode that
-supports independent sessions.
+const restored = await Oliphaunt.open({
+ topology: 'broker',
+ storage: { kind: 'directory', path: './app-data/restored.oliphaunt' },
+});
+try {
+ console.log((await restored.query('SELECT count(*) FROM notes')).rows);
+} finally {
+ await restored.close();
+}
+```
-
-
+The restored handle uses broker mode because direct mode remains bound to its original root for the lifetime of the process, even after close. Restore does not replace a nonempty database. Open with the same required extension selection. Use logical tools to move between native and WASIX.
-### Create app data
+## Choose a runtime mode
-Use the TypeScript query helpers for app code and keep the client in a service
-or framework-owned dependency container:
+Direct mode is the default. Select broker mode for a separate helper process:
```ts
-await db.execute(`
- CREATE TABLE IF NOT EXISTS notes (
- id bigserial PRIMARY KEY,
- title text NOT NULL,
- body text NOT NULL,
- created_at timestamptz NOT NULL DEFAULT now()
- )
-`);
-
-await db.query(
- 'INSERT INTO notes (title, body) VALUES ($1, $2) RETURNING id::text AS id',
- ['First note', 'Stored by embedded PostgreSQL'],
-);
-
-const notes = await db.query(
- 'SELECT id, title FROM notes ORDER BY id DESC LIMIT 20',
-);
-const firstTitle = notes.rows[0]?.title;
+const db = await Oliphaunt.open({
+ topology: 'broker',
+ storage: { kind: 'directory', path: './app-data/main.oliphaunt' },
+});
```
-For callback transactions, a callback failure is rethrown unchanged after
-automatic rollback succeeds. If rollback also fails, `AggregateError.errors`
-contains the callback failure followed by the rollback failure. If the callback
-throws a different value after an earlier independent database or protocol
-failure poisoned or expired transaction ownership, the aggregate instead
-contains the callback failure followed by that database failure and the database
-is close-only. This independent-failure case does not include an ordinary
-PostgreSQL statement error that remains safely rollbackable.
-
-Tauri apps keep the database in Rust state and expose narrow app-owned commands
-to the webview.
-
-
-
-
-### Configure
-
-Configure storage, mode, selected exact extensions, startup identity,
-PostgreSQL startup GUCs, and advanced runtime overrides through the JS
-configuration object.
-Omit `storage` for an SDK-owned temporary directory; pass
-`{ kind: 'directory', path }` for persistence.
-
-
-
-
-### Choose a mode
-
-Omit `topology` for the direct topology. Select `topology: 'broker'` when process
-isolation matters. If the helper fails, the existing database object rejects all
-later work; close it and explicitly open a new object on the same persistent
-storage for PostgreSQL WAL recovery. The SDK does not replace a session or
-replay uncertain work invisibly. Use `Oliphaunt.openServer()` when
-PostgreSQL-compatible tools and independent clients are required.
-
-
-
-
-### Handle lifecycle
-
-The client queues work through the selected runtime boundary. Close waits for
-work admitted before the close call and rejects later ordinary submissions.
-`cancel()` remains out of band while that work drains, including after the
-close admission cutoff; teardown starts only after admitted cancellation calls
-settle. Use explicit cancellation for long SQL. Call `await db.close()` or use
-`await using`; explicit close is the only deterministic way to finish session
-reset, release persistent storage ownership, and observe cleanup errors.
-
-If direct logical detachment fails before deactivation, `closed` stays false and
-the same handle may retry `close()`. Broker/server cleanup failures after their
-destructive cutoff retire the handle: `closed` becomes true, later work fails,
-and repeated `close()` calls replay the original result. A raw-protocol stream
-callback cannot reenter database/transaction work, backup, close, or another
-stream on the same handle; `cancel()` is the out-of-band exception.
-A callback error is rethrown unchanged only after the runtime confirms protocol
-recovery and leaves the session reusable. A buffered raw rejection or streamed
-execution, transport, or recovery failure is authoritative instead and poisons
-the session.
-
-Garbage-collection cleanup is a last-resort leak guard, not a lifecycle API.
-On Node/Bun, `FinalizationRegistry` passes an opaque exact-generation token to
-the addon; it releases only the matching JavaScript admission lease after the
-addon marks that generation for recovery on the next asynchronous open. Deno
-uses `FinalizationRegistry` only to enqueue nonblocking FFI
-cleanup. The Deno cleanup carries the logical generation acquired at open, so a
-late finalizer becomes a no-op instead of closing a newer lease. It performs a
-terminal native close for that process lifetime; finalizer timing is
-nondeterministic and failures cannot be reported to application code. Broker
-and server leak guards retain only the exact private runtime handle and an
-private lease generation, never the public facade. They schedule asynchronous
-teardown; an explicitly unregistered or superseded generation is a no-op. If
-leak-guard registration itself prevents facade publication, `open()` cleans up
-the opened runtime owner and releases its exact JavaScript lease before
-rejecting.
-
-
-
-
-### Select extensions
-
-Select exact SQL extension names before open. Generated resources include only
-selected extensions and mandatory dependencies.
-
-
-
-
-### Back up and restore
-
-Use `backup()` and static restore for the native physical archive. Keep live
-PostgreSQL directories behind these APIs. Restore accepts a new or
-existing-empty destination and rejects nonempty data without mutation. Native
-server applications use normal PostgreSQL tools.
-
-
-
-
-### Use logical tools
-
-Install the separate `@oliphaunt/tools` package when a server application needs
-plain `pg_dump` or non-interactive `psql`. Pass `server.connectionString` to the
-tool; the core `@oliphaunt/ts` package does not install client programs.
+Use a server when a driver or ORM needs independent PostgreSQL sessions:
```ts
-import { pgDump } from '@oliphaunt/tools';
-
-const sql = await pgDump(server.connectionString, {
- args: ['--schema-only'],
+const server = await Oliphaunt.openServer({
+ storage: { kind: 'directory', path: './app-data/server.oliphaunt' },
});
+console.log(server.connectionString);
+// Keep server in application state while clients are connected.
+// Close clients and pools before awaiting server.close().
```
-
-
+The server handle owns the process; a copied connection string does not keep it alive. The separate `@oliphaunt/tools` package provides endpoint-oriented PostgreSQL tools. See [runtime modes](/docs/learn/native-runtime).
+
+## Handle errors and shutdown
+
+PostgreSQL errors expose SQLSTATE through `PostgresError`. Use the code to distinguish expected database failures such as a constraint violation from runtime or storage failures. A transaction callback that throws is rolled back; if rollback also fails, the SDK retains both errors in an `AggregateError`.
+
+Call `db.cancel()` to interrupt active database work. Then await the operation and handle its result. Close rejects new work and drains work already accepted. Always await `close()`; garbage collection does not provide observable cleanup.
+
+After a broker crash or an unrecoverable protocol failure, close the handle and reopen persistent storage. Do not automatically replay an operation whose commit outcome is unknown.
+
+## Package an Electron app
-
+Keep `.node` modules, helper executables, and their runtime resources outside the ASAR archive. Preserve their package-relative layout so the resolver can find them. Test a packaged application on each target architecture; a development-server run does not exercise packaging.
## Troubleshooting
-Check runtime asset resolution, helper executable availability, storage ownership,
-unsupported-mode errors, extension selection, and SQLSTATE-bearing PostgreSQL
-errors.
-
-## Development resource inputs
-
-The following options describe the unreleased checkout API. They do not imply
-that new database-resource packages are available with the published version
-in the installation command above.
-
-Native Node/Bun/Deno use the same seed-validation and initialization rules.
-Pass `seed: { directory, manifestPath }` for an independently selected native
-seed directory and its producer receipt. Pass
-`icuData: { directory, manifestPath }` for the canonical ICU data directory
-and receipt. Keep these immutable resources separate from mutable database
-storage. Without a seed, supported desktop paths initialize with initdb; an
-existing database does not need its initialization seed again. ICU databases
-still require their selected ICU data. The server API uses its ordinary
-PostgreSQL initializer and does not accept a seed option.
-
-Node and Bun share the Rust-backed Node-API adapter. Deno retains its FFI host
-boundary; all three consume the same resource contract rather than separate
-package-discovery rules.
+| Symptom | Check |
+| --- | --- |
+| Native module fails to load | Runtime, operating system, architecture, and extracted package files |
+| Storage is locked | Another live handle or process owns the same root |
+| Extension is unavailable | The extension package is installed and selected before open |
+| A transaction waits indefinitely | All callback SQL uses `tx`, not the outer `db` |
+| Queries serialize | One embedded handle has one session; choose server mode for a pool |
diff --git a/src/docs/content/sdk/typescript/index.mdx b/src/docs/content/sdk/typescript/index.mdx
index 10620f637..97d9fcf52 100644
--- a/src/docs/content/sdk/typescript/index.mdx
+++ b/src/docs/content/sdk/typescript/index.mdx
@@ -1,86 +1,82 @@
---
title: TypeScript SDK
-description: Native desktop JavaScript SDK for Node.js, Bun, and Deno.
+description: Install the native SDK for Node.js, Bun, Deno, or Electron and run your first query.
---
-
+Use `@oliphaunt/ts` to run native PostgreSQL in a desktop JavaScript application. For a browser app, use [WASIX TypeScript](/docs/sdk/wasix-typescript); for a mobile app, use [React Native](/docs/sdk/react-native).
-The TypeScript SDK targets Node.js, Bun, and Deno. It is the desktop
-JavaScript SDK for the native runtime, native helpers, broker/server flows, and
-runtime asset resolution.
+## Install
-It is separate from [`@oliphaunt/wasix-ts`](/docs/sdk/wasix-typescript), whose
-browser root uses Wasmer and whose Node-compatible root, `/direct`, and
-`/worker` entrypoints use its own WASIX Rust Node-API carrier. Neither package
-selects or falls back to the other.
+The package supports Node.js 22.13 through 24.x. Bun and Deno use their native runtime adapters.
-Use this SDK for supported desktop JavaScript runtimes. Tauri apps currently
-keep the database in Rust state and expose narrow app-owned commands to the
-webview. React Native apps use the React Native SDK because mobile execution
-delegates through Swift and Kotlin.
+
+
-## Install
+```sh
+npm install @oliphaunt/ts@{{release:oliphaunt-js}}
+```
+
+
+
+
+```sh
+bun add @oliphaunt/ts@{{release:oliphaunt-js}}
+```
+
+
+
+
+Import the npm package with `import { Oliphaunt } from 'npm:@oliphaunt/ts@{{release:oliphaunt-js}}';`. Enable local npm dependencies so Deno can load the native module:
+
+```json title="deno.json"
+{ "nodeModulesDir": "auto" }
+```
-Install the package from npm:
+Allow native libraries, database files, environment variables, and the `initdb` process used to create a database:
```sh
-npm install @oliphaunt/ts@{{release:oliphaunt-js}} @oliphaunt/extension-vector
+deno run --allow-ffi --allow-env --allow-read --allow-write --allow-run main.ts
```
-npm is the native-runtime distribution for Node.js, Bun, and Deno. Deno imports
-the same package through `npm:@oliphaunt/ts`.
+
+
-Use this SDK for Node.js, Bun, and Deno. Tauri frontends currently call narrow
-app-owned Rust commands. React Native apps use `@oliphaunt/react-native` because mobile execution
-delegates through Swift and Kotlin.
+The package supplies native runtime assets for supported desktop targets. Keep native files available when bundling your application.
-## Open And Query
+## Run your first query
-Open a database from TypeScript:
+Save this example as `main.mjs` and run `node main.mjs` or `bun main.mjs`. For Deno, save it as `main.ts` and use the npm import and permissions above. It prints `42` and closes the database.
+
+
```ts
import { Oliphaunt } from '@oliphaunt/ts';
-import { vector } from '@oliphaunt/extension-vector';
+const db = await Oliphaunt.open();
+try {
+ const result = await db.query('SELECT $1::int4 AS answer', [42]);
+ console.log(result.rows[0]?.answer); // 42
+} finally {
+ await db.close();
+}
+```
+
+An open handle owns one PostgreSQL session. Queries return promises and execute in order on that session.
+
+## Keep data between runs
+
+Use this storage configuration instead of the disposable example above. Direct mode stays bound to its first root for the lifetime of the process; closing does not let the same process switch roots.
+
+Choose a persistent directory instead of the default temporary storage:
+
+```ts
const db = await Oliphaunt.open({
storage: { kind: 'directory', path: './app-data/main.oliphaunt' },
- extensions: [vector],
});
-
-const rows = await db.query('SELECT 1::text AS value');
-await db.close();
```
-## Runtime Shape
-
-The SDK detects Node.js, Bun, or Deno and selects its native direct adapter by
-default. Broker mode adds process isolation. If its helper fails, close that
-database object and open a new one on the same persistent storage; PostgreSQL
-then performs WAL recovery. Oliphaunt never substitutes a new session under the
-same object. Server mode is for PostgreSQL-compatible tools and independent
-clients.
-
-The SDK resolves local helper binaries and runtime assets for the selected
-platform. App code keeps using TypeScript promises and typed result helpers while
-the runtime mode determines whether calls use direct, broker, or server
-semantics.
-
-## App Responsibilities
-
-- Install the package-managed runtime and selected exact extension artifacts.
-- Pick broker mode when a helper process owns the database runtime.
-- Use server mode when existing PostgreSQL clients, pools, or ORMs need
- independent sessions.
-- Use SDK backup and restore APIs for export/import flows.
-- Choose direct, broker, or server from the documented runtime support matrix.
-- Await `close()` (or use `await using`) instead of relying on nondeterministic
- garbage-collection cleanup. Direct, broker, and server finalizers are
- generation/exact-handle leak guards only; their asynchronous outcome is not
- observable.
-
-## First Query
-
-Use [Build With TypeScript](/docs/sdk/typescript/guide) for open/query,
-configuration, helper resolution, lifecycle, exact extensions, backup, restore,
-and troubleshooting. Use the [API reference](/docs/sdk/typescript/api-reference)
-for the public API map.
+Reopen the same path to use the data again. Keep the handle in application state and close it when the application finishes using it.
+
+## Next steps
+
+[Query, transact, and back up data](/docs/sdk/typescript/guide), or look up methods and configuration in the [API reference](/docs/sdk/typescript/api-reference).
diff --git a/src/docs/content/sdk/wasix-rust/api-reference.md b/src/docs/content/sdk/wasix-rust/api-reference.md
index 95b142466..d1a8a0aea 100644
--- a/src/docs/content/sdk/wasix-rust/api-reference.md
+++ b/src/docs/content/sdk/wasix-rust/api-reference.md
@@ -1,121 +1,41 @@
---
-title: Rust WASIX API Reference
-description: Rust WASIX API map for protocol types, storage, extensions, and dump/restore.
+title: WASIX Rust API reference
+description: Database types, builders, queries, tools, errors, and ownership in oliphaunt-wasix.
---
-> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases.
-
-
-
-# Rust WASIX API Reference
-
-This page
-maps the Rust binding by task; it does not describe the separate
-[`@oliphaunt/wasix-ts` TypeScript API](/docs/sdk/wasix-typescript/api-reference).
-
-| Area | Public surface | Use it for |
-| --- | --- | --- |
-| Direct opening | root `Oliphaunt`, `OliphauntBuilder`, `OliphauntServerBuilder` | Open a `!Send + !Sync` database on the calling thread with memory storage by default |
-| Asynchronous handles | root `AsyncOliphaunt`, `AsyncOliphauntBuilder` | Keep an async executor responsive through cloneable handles backed by dedicated owner threads |
-| Storage | `DatabaseStorage` | Select memory or a caller-supplied host directory |
-| Single-statement SQL | `query`, `execute`, parameterized variants, fluent `sql(...).bind(...)` | Run one extended-query command and return decoded rows or a command result |
-| Multi-statement and metadata | `exec`, `describe`, fluent `describe` | Return ordered simple-query results or parameter/result OIDs without executing |
-| Parameters and rows | `TypeOid`, `Parameter`, `IntoParameter`, `ValueFormat`, `QueryRow::try_get`, `FromSql` | Encode typed/null values and decode by OID-validated index or unambiguous name while retaining raw bytes |
-| Raw protocol | `exec_protocol_raw`, `exec_protocol_raw_stream`, `RawStreamResult`, `RawStreamError` | Send PostgreSQL protocol bytes or feed bounded chunks to `()` / typed `Result<(), E>` callbacks; COPY output uses the guest stream pump |
-| Transactions | synchronous or async callback `transaction`, `TransactionResult`, `TransactionError`, `rollback`, `is_closed` | Pin the physical session, use `?` through `E: From`, and retain typed callback plus settlement failures; managed handles omit raw protocol and reject manual lifecycle ownership |
-| Lifecycle | synchronous `is_closed`, `close`; async `Clone + Send + Sync`, async `close` | Choose exclusive caller ownership or one shared FIFO, with replayable terminal teardown |
-| Server/proxy | separate `oliphaunt-pgwire-server` package: `OliphauntServer` or `AsyncOliphauntServer`, `connection_string`, `is_closed`, `close` | Use an exclusive `Send + !Sync` blocking server handle or cloneable `Send + Sync` async lifecycle handle |
-| Extensions | imported extension-crate constants, root `Extension`, catalog `ALL`, `by_sql_name` | Select independently installed WASIX artifacts and their host AOT code; migrations own `CREATE EXTENSION` |
-| Backup/restore | `Oliphaunt::backup` / `restore`; `AsyncOliphaunt::backup` / `restore` | Move the one WASIX physical archive between compatible stores |
-| Tools | database `pg_dump` / `psql`; root `tools::{PgDumpOptions, PsqlOptions, PostgresToolError}` | Run packaged PostgreSQL logical dump and non-interactive psql synchronously or asynchronously through the selected handle |
-| Diagnostics | result `notices`, `Result`, opaque `Error`, non-exhaustive `ErrorKind`, `PostgresError`, `DecodeError` | Match stable recovery categories while preserving PostgreSQL diagnostics and typed callback/settlement failures |
-
-```rust
-let result = database
- .sql("SELECT $1::int4 AS answer")
- .bind(41_i32)
- .query()?;
-let answer: i32 = result.rows()[0].try_get("answer")?;
-```
-
-## Calling and ownership contract
-
-The root is the direct API. It constructs the Wasmer store and PostgreSQL
-session on the calling thread. Database methods are synchronous, take `&mut
-self`, and have no SDK queue or message hop. A transaction borrows the database
-exclusively. Raw-stream callbacks run on that same thread and apply immediate
-backpressure before the method returns. The retained protocol attachment means
-callbacks must own `Send + 'static` captures; use `Arc>` for mutable
-state rather than borrowing the stack. Because the retained Wasmer store is thread-affine, root
-`Oliphaunt` is deliberately `!Send + !Sync`: create, use, close, and drop it on
-one OS thread. Choose `AsyncOliphaunt` when the handle itself must move or be
-shared across threads.
-
-```rust
-use oliphaunt_wasix::Oliphaunt;
-
-fn query_on_this_thread() -> oliphaunt_wasix::Result<()> {
- let mut database = Oliphaunt::open()?;
- let result = database.sql("SELECT $1::int4 AS answer").bind(41_i32).query()?;
- let answer: i32 = result.rows()[0].try_get("answer")?;
- assert_eq!(answer, 41);
- database.close()
-}
-```
-
-`AsyncOliphaunt` moves that direct implementation to a dedicated owner thread.
-It is `Clone + Send + Sync`; its async methods
-take `&self`, and every clone addresses the same session. Work, transaction
-boundaries, and close enter one FIFO in admission order. Ordinary work and
-transaction begin await a fair, bounded admission budget; saturation suspends
-the future rather than returning a queue-full error. Lifecycle controls
-do not consume that budget and cannot overtake earlier admitted work.
-Individual futures are `Send` only when their captured inputs, callbacks, and
-outputs satisfy the corresponding `Send` bounds; the handle's auto-traits do
-not override user types.
-
-```rust
-use oliphaunt_wasix::AsyncOliphaunt;
-
-async fn query_asynchronously() -> oliphaunt_wasix::Result<()> {
- let database = AsyncOliphaunt::open().await?;
- let result = database.sql("SELECT $1::int4 AS answer").bind(41_i32).query().await?;
- let answer: i32 = result.rows()[0].try_get("answer")?;
- assert_eq!(answer, 41);
- database.close().await
-}
-```
-
-Async close drains work already admitted before its atomic cutoff and rejects
-capacity waiters plus later work. A retryable close does not resurrect stale
-waiters. Concurrent callers receive the same close result. A callback
-transaction pins the session and rejects unpinned work until it settles. An
-async raw-stream callback runs synchronously on the owner thread and must not
-reenter that database. Callback errors and direct callback panics are surfaced
-only after the guest pump confirms recovery. A pump failure is authoritative,
-poisons the session until close, and is never masked by the callback outcome.
-Recovered async callback panics are `RawStreamError::CallbackPanicked` and leave
-the session reusable; pump/recovery failures are `RawStreamError::Database`.
-
-Transaction callbacks return ordinary `Result` with `E: From`.
-`CallbackAndRollback` means rollback was attempted and failed;
-`CallbackAndDatabase` means an independent database/protocol failure expired
-the transaction and host ownership was retired without sending rollback.
-
-The cross-SDK behavior follows the
-[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md).
-
-The Rust WASIX binding owns its packaged PostgreSQL runtime assets and Rust host
-behavior. Native direct, broker, and server topologies are documented in the
-native SDK sections. The WASIX TypeScript browser root runs in the importing
-realm; its Node-compatible root uses a Rust owner, `/direct` uses the importing
-realm, and `/worker` uses a package-owned JavaScript Worker.
-TypeScript exposes equivalent optional tools and a local server on
-socket-capable hosts through TypeScript-native package entry points, while
-sharing the WASIX physical backup/restore contract rather than Rust signatures.
-
-All fallible methods return the crate-owned `Result`. `Error` keeps runtime
-implementation details private, implements `std::error::Error`, and exposes
-`postgres_error()` plus `transaction_rollback_errors()` for the callback and
-rollback error pair. Use `PostgresError` when SQLSTATE and ordered backend
-error fields matter.
+Import from `oliphaunt_wasix`. The crate exports synchronous and async database types. Local server types are in the optional `oliphaunt-pgwire-server` crate.
+
+## Types and ownership
+
+| Type | Contract |
+| --- | --- |
+| `Oliphaunt` | Synchronous; neither `Send` nor `Sync`; stays on one OS thread |
+| `AsyncOliphaunt` | Cloneable `Send + Sync`; one shared owner thread and session |
+| `oliphaunt_pgwire_server::OliphauntServer` | Synchronous lifecycle for a single-client local endpoint |
+| `oliphaunt_pgwire_server::AsyncOliphauntServer` | Async lifecycle for the same endpoint model |
+
+`Oliphaunt::open()` uses `DatabaseStorage::Memory`. `.builder().storage(DatabaseStorage::Directory(path)).open()` persists data. Builders also accept `startup_guc`, `startup_gucs`, `username`, `database`, and typed `extension` selections.
+
+## Query operations
+
+`query`, `query_with_params`, `execute`, `execute_with_params`, `exec`, and `describe` expose PostgreSQL queries and metadata. `sql(...).bind(...).query()` or `.execute()` provides fluent parameter binding. Results are buffered; use `rows()` and `try_get` with compatible Rust types.
+
+`transaction(callback)` owns the session until settlement and returns `TransactionResult`. Return a result or use the transaction rollback API. Savepoints are supported; manual outer transaction-lifecycle SQL is unsupported. Transaction handles do not expose raw protocol or tools.
+
+## Data movement and tools
+
+`backup()` returns archive bytes; `Oliphaunt::restore(destination, bytes)` restores to new or empty persistent storage. `AsyncOliphaunt` offers async versions.
+
+With the `tools` feature, database handles expose `pg_dump(PgDumpOptions)` and `psql(PsqlOptions)`. The `tools` namespace supplies option and error types. Output is UTF-8 text. These methods exclusively use and reset the session.
+
+## Lifecycle and errors
+
+`close()` observes teardown and `is_closed()` reports state. Closing one async clone closes the shared session. There is no public direct-query cancellation API.
+
+`Error` implements Rust error traits. `kind()` returns a non-exhaustive `ErrorKind`; `postgres_error()` exposes PostgreSQL diagnostics including SQLSTATE. Composite transaction errors retain callback and rollback/database failures separately.
+
+## Raw protocol
+
+Buffered and callback-streamed protocol APIs belong to database handles. Stream callbacks require owned `Send + 'static` captures, including on the synchronous API. `RawStreamError` separates callback failure, callback panic, and database/recovery failure. Only confirmed recovery permits continued session use.
+
+See [Runtime behavior](/docs/sdk/wasix-rust/runtime) and [Dump and restore](/docs/sdk/wasix-rust/dump-restore) for constraints and complete examples.
diff --git a/src/docs/content/sdk/wasix-rust/dump-restore.mdx b/src/docs/content/sdk/wasix-rust/dump-restore.mdx
index dc4806e4d..3c653333b 100644
--- a/src/docs/content/sdk/wasix-rust/dump-restore.mdx
+++ b/src/docs/content/sdk/wasix-rust/dump-restore.mdx
@@ -1,180 +1,78 @@
---
-title: Rust WASIX Dump, Restore, And Upgrade
-description: Use the Rust binding's logical dumps, physical archives, CLI exports, and restore flows.
+title: Dump and restore
+description: Choose a physical backup or a logical PostgreSQL dump for data movement and upgrades.
---
-# Rust WASIX Dump, Restore, And Upgrade
+Use a physical backup for compatible WASIX restores. Use a logical SQL dump for upgrades that change the physical format or transfers between native and WASIX runtimes.
-
-The resource and package separation shown below is unreleased. Installation
-versions on this site come from completed public releases; they do not make the
-new seed, resource, or pgwire packages available. Use a coordinated source
-checkout for these examples until those products are published.
-
-
-`oliphaunt-wasix` uses the WASIX `pg_dump` binary from the separately owned
-PostgreSQL tools product for portable SQL exports, restores, and version-to-version
-upgrades.
-
-
-
-## Choose The Right Export Format
-
-Use logical dumps when you need:
-
-- a portable SQL export;
-- an upgrade path between `oliphaunt-wasix` releases;
-- a way to move data between different stores safely.
-
-Use physical archives when you need:
-
-- a same-version clone;
-- a same-runtime restore into another `oliphaunt-wasix` store;
-- a fast local backup of the current cluster state.
-
-Use logical dumps for cross-version upgrades. Keep physical archives for
-same-version clones and restores.
-
-## Tool API
-
-Enable the `tools` feature for fluent database tool methods and the optional
-`tools` options/error namespace:
+## Enable logical tools
```toml
[dependencies]
-oliphaunt-wasix = { version = "={{release:oliphaunt-wasix-rust}}", features = ["tools"] }
+oliphaunt-wasix = { version = "{{release:oliphaunt-wasix-rust}}", features = ["tools"] }
```
-Run the tools directly against an open database:
+## Export and import SQL
-```rust,no_run
+This complete example exports a database and restores it into another in-memory database:
+
+```rust
use oliphaunt_wasix::{Oliphaunt, tools};
-fn run() -> oliphaunt_wasix::Result<()> {
- let mut database = Oliphaunt::open()?;
- let sql = database.pg_dump(tools::PgDumpOptions::new().arg("--schema-only"))?;
- assert!(!sql.is_empty());
- database.close()?;
- Ok(())
-}
-```
+fn main() -> Result<(), Box> {
+ let mut source = Oliphaunt::open()?;
+ source.execute("CREATE TABLE notes (body text NOT NULL)")?;
+ source.execute("INSERT INTO notes VALUES ('First note')")?;
+ let sql = source.pg_dump(tools::PgDumpOptions::new())?;
+ source.close()?;
-The methods are available on database handles, not server or transaction
-handles. On root `Oliphaunt` they take `&mut self` and run synchronously against
-the caller-owned session. They cannot run inside a callback transaction. The tool connection resets PostgreSQL
-session state before and after it runs, so
-prepared statements and session settings on the direct handle do not survive.
-`database.pg_dump()` returns UTF-8 SQL text and `database.psql()` returns UTF-8
-standard output. Use `PsqlOptions::command(...)` for one
-command or `PsqlOptions::script(...)` for a complete SQL script. `pg_dump()`
-returns standard PostgreSQL 18 plain-text output unchanged, including its
-`COPY` data and `\\restrict`/`\\unrestrict` security delimiters.
-
-Use the same fluent methods on `AsyncOliphaunt` to run the operation through a
-dedicated database owner thread:
-
-```rust,no_run
-use oliphaunt_wasix::{AsyncOliphaunt, tools};
-
-async fn run_asynchronously() -> oliphaunt_wasix::Result<()> {
- let database = AsyncOliphaunt::open().await?;
- let sql = database.pg_dump(tools::PgDumpOptions::new()).await?;
- assert!(!sql.is_empty());
- database.close().await
+ let mut target = Oliphaunt::open()?;
+ target.psql(tools::PsqlOptions::new().script(sql))?;
+ let rows = target.query("SELECT body FROM notes")?;
+ let body: String = rows.rows()[0].try_get("body")?;
+ assert_eq!(body, "First note");
+ target.close()?;
+ Ok(())
}
```
-## `PgDumpOptions`
+`pg_dump` returns ordinary UTF-8 PostgreSQL SQL. It can contain COPY data and psql commands, so pass it to `psql`, not `execute`. The async handle exposes the same tool methods with `.await`.
-`PgDumpOptions` controls the managed parts of the dump command:
+Tools reset session state and cannot run inside a callback transaction. Restore into an empty database with required extensions available, then verify schema and data before switching the application to it.
-```rust,no_run
-use oliphaunt_wasix::tools::PgDumpOptions;
-
-let options = PgDumpOptions::new()
- .args(["--schema-only", "--quote-all-identifiers"]);
-```
+## Shape a dump
-Useful passthrough flags include dump-shaping options such as:
+Use `PgDumpOptions::new().arg("--schema-only")` for schema-only output. Other shaping options include `--quote-all-identifiers`, `-n` for a schema, and `-t` for a table.
-- `--schema-only`
-- `--quote-all-identifiers`
-- `-n `
-- `-t
`
+The SDK manages connection and output settings. Do not override host, port, username, database, file, encoding, compression, format, or parallel-job flags. This API returns uncompressed plain SQL; it does not provide custom archives or `pg_restore`.
-Managed connection and output flags are reserved by the API:
-`--file`, `--format`, `--compress`, `--encoding`, `--host`, `--port`,
-`--username`, `--dbname`, and `--jobs` are configured by Oliphaunt instead of
-`arg(...)` or `args(...)`. The returned script is always uncompressed UTF-8
-plain text.
+## Use the command line
-## CLI
-
-The CLI is also part of the crate's `tools` feature.
-
-Dump a persistent directory:
+Install the CLI with the tools feature:
```sh
-oliphaunt-wasix-dump --directory ./.oliphaunt
+cargo install oliphaunt-wasix --version {{release:oliphaunt-wasix-rust}} --features tools
+oliphaunt-wasix-dump --directory ./data/notes > notes.sql
```
-Select a non-default database or user with `--database` and `--username`. If
-the root uses installed extensions, repeat `--extension NAME` for every
-extension that must be mounted before PostgreSQL starts:
-
-```sh
-oliphaunt-wasix-dump --directory ./.oliphaunt \
- --database app --username owner \
- --extension vector --extension pg_trgm
-```
+Close other owners of that root first. Use `--database` and `--username` only for identities already present in the database. Enable required extension Cargo features at installation and repeat `--extension NAME` for each selection when dumping an extension-bearing root.
-Pass through normal `pg_dump` shaping flags after `--`:
+Pass dump-shaping arguments after `--`:
```sh
-oliphaunt-wasix-dump --directory ./.oliphaunt -- --schema-only
-oliphaunt-wasix-dump --directory ./.oliphaunt -- --quote-all-identifiers
+oliphaunt-wasix-dump --directory ./data/notes -- --schema-only
```
-## Restore
+## Restore a physical backup
-For same-version physical copies, use direct `backup()` and static
-`Oliphaunt::restore(destination, bytes)`; both are synchronous on the root API:
+```rust
+let archive = db.backup()?;
+db.close()?;
+Oliphaunt::restore("./data/restored", archive)?;
+```
-```rust,no_run
-use oliphaunt_wasix::Oliphaunt;
+This fragment assumes an open source `db`. The destination must be absent or empty. Restore does not replace a nonempty root. Reopen it with a compatible WASIX runtime and the required extension selection.
-fn clone_database() -> oliphaunt_wasix::Result<()> {
- let mut source = Oliphaunt::open()?;
- let archive = source.backup()?;
- source.close()?;
- Oliphaunt::restore("./restored", archive)
-}
-```
+## Upgrade application data
-Physical restore accepts an absent or empty managed-root directory and
-publishes a new root only after validating and staging the complete archive.
-The root call runs to completion or returns an error. The async
-`AsyncOliphaunt::restore` uses a temporary owner thread; once publication
-starts, abandoning its future does not promise cancellation.
-
-For a logical restore, run
-`database.psql(PsqlOptions::new().script(sql))`. Do not pass the
-script to `database.execute(...)`: plain `pg_dump` output can include `psql`
-meta commands. Oliphaunt does not expose a second logical-restore abstraction.
-With an async handle, await the corresponding
-`database.psql(...).await` call.
-
-## Upgrade Guidance
-
-Use logical dump and restore when upgrading between `oliphaunt-wasix` versions or
-changing shipped runtime assets:
-
-1. Open the old database with the old crate/runtime.
-2. Create a logical dump with `database.pg_dump(...)`, or use
- `oliphaunt-wasix-dump`.
-3. Open a fresh database with the new crate/runtime.
-4. Feed the script through
- `database.psql(PsqlOptions::new().script(sql))`.
-
-Use logical dumps for general upgrades. Physical data-dir archives are for the
-same runtime family and database format.
+Keep a recoverable copy of the old data. Read the SDK and runtime release notes, choose physical restore only when compatibility is documented, and otherwise export logical SQL with the old runtime. Import into a fresh database with the new runtime, verify application queries and constraints, then switch the app to the new root.
diff --git a/src/docs/content/sdk/wasix-rust/guide.mdx b/src/docs/content/sdk/wasix-rust/guide.mdx
index 5e7bf8510..2bbecb72d 100644
--- a/src/docs/content/sdk/wasix-rust/guide.mdx
+++ b/src/docs/content/sdk/wasix-rust/guide.mdx
@@ -1,297 +1,85 @@
---
-title: Build With Rust WASIX
-description: Use the Rust WASIX binding with memory by default, explicit persistence, selected extensions, and data-movement tools.
+title: WASIX Rust guide
+description: Use typed queries, transactions, extensions, backups, and async execution.
---
-# Build With Rust WASIX
+These recipes use a mutable synchronous `db` from the [WASIX Rust quickstart](/docs/sdk/wasix-rust). The async API exposes equivalent operations with `.await`.
-
-The resource and package separation shown below is unreleased. Installation
-versions on this site come from completed public releases; they do not make the
-new seed, resource, or pgwire packages available. Use a coordinated source
-checkout for these examples until those products are published.
-
-
-Use `oliphaunt-wasix` when Rust owns the WASIX host. This crate is separate
-from every native SDK and from the WASIX TypeScript binding.
-
-
-Browser, Node, Bun, Deno, and Electron TypeScript applications use [`@oliphaunt/wasix-ts`](/docs/sdk/wasix-typescript). The Rust
-and TypeScript bindings consume the portable WASIX runtime family. Rust uses a
-synchronous caller-thread root or explicit root `Async*` owner types. TypeScript
-uses a caller-realm browser root; on Node.js, Bun, Deno, and Electron its root
-uses a Rust actor, `/direct` selects blocking caller-thread execution, and
-`/worker` selects a real package-owned Worker. Signatures remain idiomatic to
-each language.
-
-
-
-
-
-
-
-### Install
-
-Add the Rust binding. The package resolves its matching portable runtime and
-host AOT artifacts; application code does not configure archive URLs.
-
-```sh
-cargo add oliphaunt-wasix@={{release:oliphaunt-wasix-rust}}
-```
-
-
-
-
-### Open and query
-
-Omitting storage opens a fresh in-memory database initialized with initdb when no seed is selected. The crate root returns an exclusive direct handle; fallible
-database operations are synchronous and take `&mut self`.
-
-```rust
-use oliphaunt_wasix::Oliphaunt;
-
-fn run() -> oliphaunt_wasix::Result<()> {
- let mut database = Oliphaunt::open()?;
- let result = database.query("SELECT 1::text AS value")?;
-
- let value: &str = result.rows()[0].try_get("value")?;
- assert_eq!(value, "1");
- database.close()?;
- Ok(())
-}
-```
-
-
-
-
-### Create app data
-
-Use ordinary PostgreSQL SQL and positional parameters:
-
-```rust
-database.execute(
- "CREATE TABLE IF NOT EXISTS notes (id bigserial PRIMARY KEY, title text NOT NULL)",
-)?;
-database.execute_with_params(
- "INSERT INTO notes (title) VALUES ($1)",
- ["First note"],
-)?;
-
-let notes = database.query_with_params(
- "SELECT id, title FROM notes ORDER BY id DESC LIMIT $1",
- [20_i32],
-)?;
-let first_title: String = notes.rows()[0].try_get("title")?;
-```
-
-
-
-
-### Configure
-
-Select persistence only when the application needs it:
+## Query application data
```rust
-use oliphaunt_wasix::{DatabaseStorage, Oliphaunt};
-
-let mut database = Oliphaunt::builder()
- .storage(DatabaseStorage::Directory("./app-data/main".into()))
- .open()?;
+db.execute("CREATE TABLE IF NOT EXISTS notes (body text NOT NULL)")?;
+db.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["First note"])?;
+let result = db.query("SELECT body FROM notes")?;
+let body: String = result.rows()[0].try_get("body")?;
```
-`DatabaseStorage::Memory` is the default. `Directory` uses a caller-owned host
-directory; its Rust path must be nonempty and contain no NUL bytes.
-Applications resolve temporary or platform app-data paths with their preferred
-host library. New stores use initdb unless the caller supplies a separately selected seed.
-
-In this development checkout, supply `.seed(ClusterSeed::new(archive, manifest))`
-to either builder. Independent seed Cargo carriers expose `seed_archive()` and
-`seed_manifest()`. Supply raw canonical ICU data and its receipt through
-`.icu_data(IcuData::new(data, manifest)?)`; this validates the data and selects
-ICU. Standard opens do not require ICU. Existing roots do not need a seed,
-but ICU roots still require their ICU data on every open.
-
-
-
-
-### Choose execution placement
-
-Use the root `Oliphaunt` for the normal direct contract. PostgreSQL runs on the
-calling thread with no SDK queue or message hop. Database and transaction
-methods take `&mut self`. Its retained Wasmer store is thread-affine, so the
-handle is `!Send + !Sync` and its full lifetime must remain on that OS thread:
-
-```rust
-use oliphaunt_wasix::Oliphaunt;
-
-fn run_direct() -> oliphaunt_wasix::Result<()> {
- let mut database = Oliphaunt::open()?;
- database.execute("CREATE TABLE notes (title text NOT NULL)")?;
- database.close()
-}
-```
+Use bound parameters for values. Match Rust result types to PostgreSQL column types and use `Option` for nullable values.
-Use `oliphaunt_wasix::AsyncOliphaunt` when an async application needs a
-cloneable `Send + Sync` handle and dedicated owner-thread execution:
+## Run a transaction
```rust
-use oliphaunt_wasix::AsyncOliphaunt;
-
-async fn run_asynchronously() -> oliphaunt_wasix::Result<()> {
- let database = AsyncOliphaunt::open().await?;
- database.execute("CREATE TABLE notes (title text NOT NULL)").await?;
- database.close().await
-}
+db.transaction(|tx| {
+ tx.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["First"])?;
+ tx.execute_with_params("INSERT INTO notes (body) VALUES ($1)", ["Second"])?;
+ Ok::<_, oliphaunt_wasix::Error>(())
+})?;
```
-The handle's auto-traits do not make every user-created future unconditionally
-`Send`: a future is `Send` only when the values, callback captures, and output
-types it carries across suspension points are also `Send`.
-
-The development checkout moves the socket adapter into the separate
-`oliphaunt-pgwire-server` crate; it is not yet a published install target.
-Use `oliphaunt_pgwire_server::OliphauntServer` only when an existing PostgreSQL client library
-needs a local connection URL. Its `start()` and `close()` lifecycle is
-synchronous, while its listener thread owns the single-backend wire server.
-The blocking handle is movable (`Send`) but exclusive (`!Sync`).
-`AsyncOliphauntServer` offers cloneable `Send + Sync` async lifecycle calls.
-Loopback TCP listeners are available on every supported host; Unix-domain
-listeners and `ServerListen::unix*` are available only on Unix hosts. Neither
-server handle is an alias for native direct, broker, or server topology.
-
-
-
+Return `Ok` to commit or `Err` to roll back. Use the transaction handle for all callback SQL. Manual outer transaction-lifecycle SQL is unsupported; use the rollback API or savepoints instead.
-### Handle lifecycle
+## Select extensions
-Close the root database explicitly with `close()`. Once shutdown starts, the
-handle is permanently retired: `is_closed()` is true, later work is rejected,
-and later close calls replay the terminal result. A direct callback transaction
-attempts rollback synchronously before resuming a callback panic and poisons
-the database if settlement is uncertain. The direct server keeps its handle
-across `close(&mut self)`, exposes `is_closed()`, and replays its first terminal
-close result.
-
-On an async handle, `close().await` establishes an ordered FIFO cutoff. Work
-already in the owner FIFO drains; capacity waiters and later work are rejected.
-A retryable close does not resurrect stale waiters. Concurrent close callers
-receive the same result. Dropping the last clone starts best-effort cleanup but
-does not wait for it, so explicit close remains the durable lifecycle boundary.
-An async transaction-body panic unwinds the awaiting task immediately. Dropping
-the still-active transaction enqueues best-effort rollback in FIFO order; the
-unwind does not wait for that rollback, but later database work cannot overtake
-it.
-
-Persistent directories have exclusive ownership: a second database or server
-open against the same directory returns a lock error instead of starting
-another backend.
-
-
-
-
-### Select extensions
-
-Add each independently released extension crate with its `wasix` feature and
-select its typed value on the builder. Selection makes the artifact
-and required pre-start settings available; it does not run `CREATE EXTENSION`,
-`LOAD`, or migration SQL. Optional extension payloads are not part of the core
-runtime. The selected crate carries its portable bytes and matching host AOT
-code. `Extension::ALL` and `Extension::by_sql_name` describe catalog metadata;
-bare selectors require payloads enabled through the older `extension-*` features.
+Add the extension crate with its WASIX feature:
```toml
[dependencies]
-oliphaunt-wasix = "={{release:oliphaunt-wasix-rust}}"
-oliphaunt-extension-pgtap = { version = "={{release:oliphaunt-extension-pgtap}}", default-features = false, features = ["wasix"] }
+oliphaunt-wasix = "{{release:oliphaunt-wasix-rust}}"
+oliphaunt-extension-pgtap = { version = "{{release:oliphaunt-extension-pgtap}}", default-features = false, features = ["wasix"] }
```
+Select it before opening, then enable it with SQL:
+
```rust
use oliphaunt_wasix::Oliphaunt;
-let mut database = Oliphaunt::builder().extension(oliphaunt_extension_pgtap::PGTAP).open()?;
-database.execute("CREATE EXTENSION pgtap")?;
+let mut db = Oliphaunt::builder()
+ .extension(oliphaunt_extension_pgtap::PGTAP)
+ .open()?;
+db.execute("CREATE EXTENSION IF NOT EXISTS pgtap")?;
```
-
-
+Reopen persistent databases with the same required extension selection. The [extension catalog](/docs/reference/extension-catalog) lists supported names and targets.
-### Back up, dump, and restore
-
-Use `backup()` and static `Oliphaunt::restore(destination, bytes)` for the one
-same-version WASIX physical archive. Enable the crate's `tools` feature for
-`pg_dump` and `psql` when portable logical SQL or version upgrades are needed.
-Do not copy a live PostgreSQL directory.
+## Back up and restore
```rust
-let archive = database.backup()?;
-database.close()?;
-Oliphaunt::restore("./app-data/restored", archive)?;
+let archive = db.backup()?;
+db.close()?;
+oliphaunt_wasix::Oliphaunt::restore("./data/restored", archive)?;
```
-
-
-
-### Use transactions
+The destination must be new or empty. Use a compatible WASIX runtime for physical restore, and ship required extensions separately. For SQL export and upgrades, see [Dump and restore](/docs/sdk/wasix-rust/dump-restore).
-The direct callback receives an exclusive `&mut Transaction`. Success commits,
-callback failure rolls back, and `rollback()` explicitly rolls back without a
-later commit. Callbacks return ordinary `Result` with
-`E: From`, so database calls use `?` while an
-application may return its own typed abort:
-
-```rust
-database.transaction(|transaction| {
- transaction.execute_with_params(
- "INSERT INTO notes (title) VALUES ($1)",
- ["Transactional note"],
- )?;
-
- let count = transaction.query("SELECT count(*)::int8 AS count FROM notes")?;
- let count: i64 = count.rows()[0].try_get("count")?;
- assert!(count > 0);
- Ok::<(), oliphaunt_wasix::Error>(())
-})?;
-```
+## Configure startup
-The explicit success error type is needed only when surrounding code does not
-otherwise choose `E`; it keeps the generic callback free to use an application
-error type when one is available.
+Use the builder's `startup_guc(name, value)`, `username(...)`, and `database(...)` methods. Fresh roots use the `postgres` role and database. Selecting another identity does not create it.
-The transaction borrow prevents unrelated direct work until the callback
-settles. With `AsyncOliphaunt`, the callback is async and receives an exclusive
-`&mut AsyncTransaction`; work through another database clone is rejected while
-the transaction is pinned. Dropping an active async transaction future queues
-best-effort rollback in FIFO order. `TransactionError::CallbackAndRollback`
-means rollback was actually attempted and failed. `CallbackAndDatabase` means
-an independent database or protocol failure expired the transaction and no
-rollback was sent.
+## Use async execution
-Managed transaction handles intentionally omit raw-protocol methods. Do not
-issue `BEGIN`, `COMMIT`, `END`, `ROLLBACK`, or `AND CHAIN` through their
-structured SQL methods; let the callback settle or call `rollback()`. Savepoints
-and `ROLLBACK TO SAVEPOINT` remain supported. The root raw-protocol adapter is
-the escape hatch for callers that deliberately own PostgreSQL session state.
+Use `AsyncOliphaunt` to keep blocking guest execution off an async executor. Cloned handles share the same session. Closing any clone closes it for all callers.
-Direct raw-stream callbacks run synchronously before the method returns, but
-the retained WASIX stdio attachment requires owned `Send + 'static` captures;
-use `Arc>` for mutable callback state. Return `()` for infallible
-delivery or `Result<(), E>` for a typed stop. A direct callback panic resumes
-only after confirmed pump recovery. A recovered async owner callback panic is
-`RawStreamError::CallbackPanicked`. Async callbacks also require owned
-`Send + 'static` captures and can use `Arc>` for shared mutable state.
-An independent pump/recovery failure is
-`RawStreamError::Database`, takes precedence, and poisons the session.
+The synchronous handle remains on one OS thread for its entire lifetime. Do not move it into a generic blocking pool between calls. See [runtime ownership](/docs/sdk/wasix-rust/runtime).
-
-
+## Errors and shutdown
-
+Inspect `error.kind()` and `error.postgres_error()` for structured failures. PostgreSQL errors include SQLSTATE. Transaction errors preserve callback and rollback/database failures when both occur.
-## Troubleshooting
+Close explicitly to observe shutdown errors. After a terminal failure, stop using the handle and reopen persistent storage when appropriate. The SDK does not expose direct-query cancellation; dropping a future does not guarantee that an already-running statement stops.
-Check whether the selected managed root is new or complete, any explicitly selected
-seed and exact runtime/AOT asset pair, enabled extension features,
-directory ownership, and SQLSTATE-bearing
-PostgreSQL errors. Browser, Node, Bun, Deno, and Electron actor/direct/Worker behavior, the
-explicit `/worker` entry point, IndexedDB, and recovery behavior are documented
-on the [WASIX TypeScript guide](/docs/sdk/wasix-typescript/guide).
+| Symptom | Check |
+| --- | --- |
+| Cannot send the handle to another thread | Use `AsyncOliphaunt` or keep the synchronous handle on its original thread |
+| Directory is locked | Another process, Worker, or binding owns the root |
+| Extension constant is unavailable | Add the extension crate with its `wasix` feature |
+| SQL dump fails to import through `execute` | Use the `psql` tool to handle COPY and psql commands |
diff --git a/src/docs/content/sdk/wasix-rust/index.mdx b/src/docs/content/sdk/wasix-rust/index.mdx
index c41bd0409..be6023843 100644
--- a/src/docs/content/sdk/wasix-rust/index.mdx
+++ b/src/docs/content/sdk/wasix-rust/index.mdx
@@ -1,117 +1,62 @@
---
-title: Rust WASIX SDK
-description: Host the portable Oliphaunt WASIX runtime from Rust with memory by default and explicit persistence.
+title: WASIX Rust SDK
+description: Host WebAssembly PostgreSQL from Rust with memory or persistent directory storage.
---
-> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases.
+Use `oliphaunt-wasix` when a Rust application hosts the WASIX PostgreSQL runtime. For native desktop PostgreSQL, use the [native Rust SDK](/docs/sdk/rust).
+## Install
+```toml
+[dependencies]
+oliphaunt-wasix = "{{release:oliphaunt-wasix-rust}}"
+```
-
-
-`oliphaunt-wasix` is the Rust binding for the portable WASIX runtime. It keeps
-its package, runtime assets, extensions, storage, and behavior separate from
-the native SDK products.
-
-The crate root is the default direct API. `Oliphaunt` constructs and retains the
-Wasmer store and PostgreSQL session on the calling thread; its synchronous
-database methods take `&mut self`. The retained store is thread-affine, so this
-root handle is `!Send + !Sync` and must be created, used, closed, and dropped on
-one OS thread. Applications that need a movable/shared handle or need to keep an
-async executor responsive use the cloneable `Send + Sync` root
-`AsyncOliphaunt` type. That choice is explicit and does not change storage or
-SQL semantics.
-
-Use this SDK when Rust owns the WASIX host. Native desktop and mobile apps use
-native SDKs when they select `liboliphaunt`. Browser, Node, Bun, Deno, and Electron TypeScript apps can use the
-separate [`@oliphaunt/wasix-ts` TypeScript binding](/docs/sdk/wasix-typescript);
-the two bindings share runtime and storage formats while keeping language-native APIs.
+The package resolves matching runtime assets for supported hosts. Use Rust 1.93 or later.
-## Install
+## Run your first query
-Install the Rust WASIX package. Consumer applications receive the matching
-portable runtime and target AOT artifacts through package-manager dependencies.
+Create a complete `src/main.rs`:
-For Rust hosts:
+
-```sh
-cargo add oliphaunt-wasix@={{release:oliphaunt-wasix-rust}}
+```rust
+use oliphaunt_wasix::Oliphaunt;
+
+fn main() -> Result<(), Box> {
+ let mut db = Oliphaunt::open()?;
+ let result = db.sql("SELECT $1::int4 AS answer").bind(42_i32).query()?;
+ let answer: i32 = result.rows()[0].try_get("answer")?;
+ println!("{answer}"); // 42
+ db.close()?;
+ Ok(())
+}
```
-## Open And Query
+Run with `cargo run`. The default database uses a memory filesystem and is discarded on close.
-Open the direct Rust API for ordinary embedded use. Storage defaults to a true
-in-memory WASIX filesystem. The exclusive handle makes caller-thread execution
-and ordering visible in the type system:
+## Keep data between runs
```rust
use oliphaunt_wasix::{DatabaseStorage, Oliphaunt};
-fn run() -> oliphaunt_wasix::Result<()> {
- let mut database = Oliphaunt::open()?;
- let rows = database.query("select 1::text as value")?;
+let mut db = Oliphaunt::builder()
+ .storage(DatabaseStorage::Directory("./data/notes".into()))
+ .open()?;
+```
- // For persistence, select a caller-owned host directory instead:
- // let mut database = Oliphaunt::builder()
- // .storage(DatabaseStorage::Directory("./app-data/main.oliphaunt".into()))
- // .open()?;
+Only one live owner can open a persistent root. Reopen the same path to access saved data.
- let value: &str = rows.rows()[0].try_get("value")?;
- assert_eq!(value, "1");
- database.close()?;
- Ok(())
-}
-```
+## Choose synchronous or async ownership
-For a dedicated owner thread, use the asynchronous type explicitly:
+The synchronous `Oliphaunt` is **not `Send` or `Sync`**. Create, use, close, and drop it on the same OS thread. Use `AsyncOliphaunt` for a cloneable `Send + Sync` handle:
```rust
use oliphaunt_wasix::AsyncOliphaunt;
-async fn run_asynchronously() -> oliphaunt_wasix::Result<()> {
- let database = AsyncOliphaunt::open().await?;
- let rows = database.query("select 1::text as value").await?;
- let value: &str = rows.rows()[0].try_get("value")?;
- assert_eq!(value, "1");
- database.close().await
-}
+let db = AsyncOliphaunt::open().await?;
+let result = db.query("SELECT 42::int4 AS answer").await?;
+db.close().await?;
```
-## Runtime Shape
-
-Rust WASIX is separate from native direct, native broker, and native server. It
-has its own filesystem, startup, server/proxy, dump/restore, and extension
-behavior.
-
-The Rust binding exposes the default direct caller-thread API, named root
-`Async*` handles, optional `pg_dump`/`psql`, and a local
-PostgreSQL-compatible URL. WASIX TypeScript chooses placement at the package
-boundary: browser root runs in the importing realm, the native-host root uses the Rust
-owner actor, `/direct` selects caller-thread execution, and `/worker` selects a
-package-owned JavaScript Worker.
-Optional tools and the Node, Bun, Deno, and Electron host-only `/server` subpath remain
-language-specific.
-
-Applications that need a real concurrent PostgreSQL listener on Linux x64 GNU or macOS arm64
-can instead deploy the separate [WASIX postmaster](/docs/sdk/wasix-rust/runtime#wasix-postmaster)
-sealed carrier. It is a peer runtime product, not an execution mode hidden in
-the single-backend SDK.
-
-## App Responsibilities
-
-- Depend on the portable runtime artifact and target-specific AOT artifact for
- each supported host.
-- Install exact WASIX extension packages for the SQL extensions your app uses.
-- Use the WASIX runtime guide for storage, server/proxy, and startup behavior.
-- Use dump and restore flows for portable data movement and upgrades.
-- Do not mix the crate's server or tool APIs into
- WASIX TypeScript examples.
-
-## First Query
-
-Use [Build With Rust WASIX](/docs/sdk/wasix-rust/guide) for the first query and
-runtime configuration. Use [Rust WASIX runtime](/docs/sdk/wasix-rust/runtime) for
-server/proxy and asset behavior, and [dump and restore](/docs/sdk/wasix-rust/dump-restore)
-for data movement. TypeScript applications start with
-[WASIX TypeScript](/docs/sdk/wasix-typescript). Concurrent server
-deployments start with [WASIX postmaster](/docs/sdk/wasix-rust/runtime#wasix-postmaster).
+Async clones share one owner and session. Continue with the [WASIX Rust guide](/docs/sdk/wasix-rust/guide), [runtime behavior](/docs/sdk/wasix-rust/runtime), or [API reference](/docs/sdk/wasix-rust/api-reference).
diff --git a/src/docs/content/sdk/wasix-rust/runtime.mdx b/src/docs/content/sdk/wasix-rust/runtime.mdx
index 51d600288..b570bd890 100644
--- a/src/docs/content/sdk/wasix-rust/runtime.mdx
+++ b/src/docs/content/sdk/wasix-rust/runtime.mdx
@@ -1,165 +1,55 @@
---
-title: Rust WASIX Runtime Guide
-description: Rust WASIX memory, persistent storage, startup, server, tools, and physical archive behavior.
+title: WASIX Rust runtime
+description: Understand thread ownership, persistent roots, local endpoints, and shutdown.
---
-# Rust WASIX Runtime Guide
-
-
-The resource and package separation shown below is unreleased. Installation
-versions on this site come from completed public releases; they do not make the
-new seed, resource, or pgwire packages available. Use a coordinated source
-checkout for these examples until those products are published.
-
-
-`oliphaunt-wasix` is the Rust host for the portable runtime. It shares the
-PostgreSQL guest and physical contracts with
-[`@oliphaunt/wasix-ts`](/docs/sdk/wasix-typescript), while keeping Rust-native
-filesystem, server, tool, and error APIs.
-
-
-
-## Direct and server hosts
-
-Use the root `Oliphaunt` when Rust code calls the database directly. It is a
-synchronous, exclusive handle: open constructs the Wasmer store and PostgreSQL
-session on the calling thread, and database methods take `&mut self`. There is
-no SDK queue or message hop. The store is thread-affine, making the handle
-`!Send + !Sync`; its complete create/use/close/drop lifetime stays on one OS
-thread.
-
-Use `AsyncOliphaunt` when an async application needs a cloneable `Send +
-Sync` handle. Open constructs the direct database on a dedicated owner thread;
-every clone submits work to that same session through `&self` and awaits the
-result.
-
-Use `oliphaunt_pgwire_server::OliphauntServer` when an existing PostgreSQL client library needs
-a local endpoint. Loopback TCP is available on every supported host;
-Unix-domain sockets are available only on Unix hosts. Its `start()` and
-`close()` lifecycle is synchronous; `AsyncOliphauntServer` provides async
-lifecycle calls. In both cases the server owns its listener and one embedded
-WASIX backend. It accepts one connected client at a time and does not turn the
-runtime into a multi-backend postmaster. It is not a network view over an
-existing direct `Oliphaunt` handle.
-
-The embedded proxy uses PostgreSQL trust authentication, so TCP endpoints are
-fixed to IPv4 loopback. The default assigns a port automatically; use
-`ServerListen::tcp_port` for a fixed TCP port on any supported host. On Unix
-hosts only, use `ServerListen::unix` or `ServerListen::unix_port` for a
-PostgreSQL-style Unix socket directory.
-
-## Explicit asynchronous surface
-
-Use `oliphaunt_wasix::AsyncOliphaunt` or the separate
-`oliphaunt_pgwire_server::AsyncOliphauntServer` type when the application
-deliberately wants a dedicated execution owner. The async database and server wrap the same direct
-implementations with async methods. Database clones share one physical session
-and one ordered FIFO. Do not mix synchronous and async handles or infer that
-`DatabaseStorage::Memory` or `Directory` chooses an execution contract.
-
-The synchronous and async surfaces use the same PostgreSQL behavior, storage formats,
-result types, extensions, raw protocol, and data-movement formats. They differ
-only in ownership and calling semantics.
-
-## Storage
-
-`DatabaseStorage::Memory` is the default true Wasmer memory filesystem.
-`DatabaseStorage::Directory(path)` is a caller-owned managed root. A new store
-uses initdb or an explicitly selected seed; reopening needs no seed and validates the descriptor
-and minimal PostgreSQL markers. The caller-supplied Rust path must be nonempty
-and contain no NUL bytes. Incomplete or descriptorless nonempty roots fail
-without mutation.
-
-Physical restore on the root surface is the synchronous static
-`Oliphaunt::restore(destination, bytes)` operation. It accepts a new or empty
-destination and returns after publication finishes or fails. The async
-`AsyncOliphaunt::restore(...).await` performs the same work on a temporary
-owner thread; once publication starts, abandoning the future does not promise
-cancellation. The runtime retains its initializer, so omitting a seed is a supported new-store path.
-
-## Startup and extensions
-
-Builders accept username, database, validated PostgreSQL startup GUCs, and
-exact typed extension selections. Reopening an extension-bearing root requires
-the receiving host to select the installed extension code again.
-
-## Data movement and tools
-
-Root `backup()` and async `backup().await` produce the one WASIX PostgreSQL 18
-physical archive. Each binding qualifies restore through its own storage
-provider; cross-binding root/archive transfer is not a supported workflow.
-Enable the Rust crate's
-`tools` feature for `database.pg_dump(options)` and `database.psql(options)`.
-The same fluent methods on `AsyncOliphaunt` return futures and queue an
-exclusive owner operation. The root `tools` namespace contains only option and
-structured-error types. Logical SQL is the portable upgrade and native/WASIX
-transfer path.
-
-## Lifecycle
-
-Persistent directories have one Rust host owner while open. Close a root
-database explicitly with `close()`. Once database shutdown or server stop
-begins, the handle is permanently retired: `is_closed()` is true, later work is
-rejected, and later close calls replay the terminal result. A direct transaction
-borrows the database until it settles. A direct callback panic attempts
-rollback synchronously and resumes only when settlement is known; an uncertain
-outcome poisons the database until close.
-
-Close an async database with `close().await`; closing any clone closes the
-shared session. Concurrent callers await one immutable close attempt and
-receive its same success or failure. Pre-shutdown validation leaves the database
-open for a later retry. Dropping the last clone initiates best-effort cleanup
-without waiting for the owner thread, so it is not a replacement for explicit
-close. Close connected clients before calling direct `OliphauntServer::close()`
-or awaiting `AsyncOliphauntServer::close()`.
-
-Async database operations, transaction boundaries, and close enter one owner
-queue in admission order. Ordinary work and transaction begin await a fair,
-bounded 64-entry admission budget; saturation suspends the future rather than
-returning a queue-full error. Lifecycle controls do not consume that budget,
-but remain in the same owner order and cannot overtake earlier admitted work.
-Starting close establishes an atomic cutoff: work already in the owner FIFO
-drains, while capacity waiters and later ordinary work are rejected. A retryable
-close does not resurrect pre-cutoff waiters. Work dropped before owner execution
-is skipped without disturbing the order; once execution starts, PostgreSQL runs
-to a readiness boundary. Dropping an active transaction queues best-effort
-rollback. Callback transactions pin the physical session, and unpinned work is
-rejected until the transaction settles. Server clients use their own socket
-sessions and are not part of this async owner queue.
-
-An async transaction-body panic unwinds its awaiting task without waiting for
-rollback. Dropping the active transaction enqueues best-effort rollback in the
-same FIFO, so later database work cannot overtake cleanup even though cleanup
-has not completed when the unwind reaches the caller.
-
-The direct raw-stream callback delivers bounded chunks on the calling thread,
-providing backpressure while the guest protocol pump streams COPY output. It
-still requires owned `Send + 'static` captures because its stdio attachment is
-retained for the session; use `Arc>` for mutable state. The async
-callback runs on the owner thread and must not reenter the same database;
-reentrancy is rejected rather than deadlocking. Return `()` for infallible
-delivery or `Result<(), E>` for a typed stop. A callback error is
-`RawStreamError::Callback` only after the pump confirms recovery. A recovered
-direct callback panic resumes on the caller; a recovered async callback panic
-is `RawStreamError::CallbackPanicked` and leaves the session reusable. An
-independent pump failure is `RawStreamError::Database`, takes precedence,
-poisons the session until close, and suppresses any retained direct callback
-unwind. WASIX query cancellation
-remains unavailable until the guest can interrupt execution and prove protocol
-recovery; typed COPY helpers remain deferred in the shared SDK parity policy.
-
-## Errors
-
-Fallible methods return `oliphaunt_wasix::Result`. The opaque SDK `Error`
-implements the standard Rust error traits, exposes non-exhaustive `ErrorKind`
-through `kind()`, and supports `postgres_error()`.
-PostgreSQL `ErrorResponse` failures expose `PostgresError`, which provides
-SQLSTATE plus the ordered raw fields without leaking host implementation error
-types into the public API.
-
-## Supported hosts
-
-Published packages carry the runtime artifacts for their documented targets.
-Missing target assets fail during open. Support is recorded in the
-[static runtime matrix](/docs/reference/capabilities), not discovered through a
-capability object.
+The WASIX Rust SDK owns a WebAssembly host and one PostgreSQL backend. Choose its synchronous or async API according to how your application schedules work.
+
+## Thread ownership
+
+`Oliphaunt` is neither `Send` nor `Sync` and must stay on one OS thread, including close and drop.
+
+`AsyncOliphaunt` owns the runtime on a dedicated thread. Calls execute in admission order, and clones share one session. Async placement changes scheduling, not SQL concurrency.
+
+## Persistent storage
+
+Only one live owner can open a persistent database. Let the SDK manage its files; do not copy a live directory or delete locks to force a second owner.
+
+Use the backup API for data movement. Physical restore requires matching runtime-family and format compatibility. Logical SQL is the transfer path across native/WASIX families or incompatible versions.
+
+## Local PostgreSQL endpoint
+
+Add the optional server crate when a PostgreSQL client needs a connection string:
+
+```toml
+oliphaunt-pgwire-server = "{{release:oliphaunt-pgwire-server}}"
+```
+
+```rust
+use oliphaunt_pgwire_server::{DatabaseStorage, OliphauntServer};
+
+let mut server = OliphauntServer::builder()
+ .storage(DatabaseStorage::Directory("./data/server".into()))
+ .start()?;
+println!("{}", server.connection_string());
+// Connect one client. Close it before closing the server.
+server.close()?;
+```
+
+The endpoint serves one connected client at a time. Configure pools with a maximum of one connection. Use `AsyncOliphauntServer` for async lifecycle ownership. For independent client sessions, choose the [native server](/docs/learn/native-runtime#server).
+
+## Shutdown and failures
+
+Closing rejects new work and drains work already accepted. A terminal shutdown attempt retires the handle even when it returns an error. A validation failure before shutdown begins can leave it open; inspect the operation's result rather than assuming cleanup completed.
+
+An async transaction dropped before settlement queues best-effort rollback. This preserves operation ordering but does not promise that rollback has finished before the calling task unwinds. Explicit transaction settlement and close make outcomes observable.
+
+## Raw response streaming
+
+Raw callbacks receive PostgreSQL protocol chunks, not typed rows. Both placements require owned `Send + 'static` captures. Use a shared synchronized container when collecting mutable callback state.
+
+A callback can return `()` or a typed result. A callback-only failure allows reuse only after confirmed protocol recovery. An independent database failure takes precedence and makes the session close-only. Do not re-enter the database from its callback.
+
+## Optional tools
+
+Enable the `tools` feature for `pg_dump` and non-interactive `psql`. Tools exclusively own and reset the session, so session settings and prepared statements may need to be recreated afterward. See [Dump and restore](/docs/sdk/wasix-rust/dump-restore).
diff --git a/src/docs/content/sdk/wasix-typescript/api-reference.md b/src/docs/content/sdk/wasix-typescript/api-reference.md
index 601b36c01..42ae2791f 100644
--- a/src/docs/content/sdk/wasix-typescript/api-reference.md
+++ b/src/docs/content/sdk/wasix-typescript/api-reference.md
@@ -1,92 +1,54 @@
---
-title: WASIX TypeScript API Reference
-description: Public API map for portable TypeScript database, storage, query, and physical archive operations.
+title: WASIX TypeScript API reference
+description: Imports, storage descriptors, configuration, methods, and runtime-specific constraints.
---
-> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases.
-
-
-
-# WASIX TypeScript API Reference
-
-
-| Area | Public surface | Purpose |
-| --- | --- | --- |
-| Client | `Oliphaunt.open`, `Oliphaunt.restore` | Open a database or restore an archive into persistent storage |
-| Single-statement SQL | decoded `query`, byte-preserving `queryRaw`, `execute` | Read object or array rows, retain exact wire rows, or assert that a command returns no rows |
-| Multi-statement and metadata | `exec`, `describe` | Return simple-query results in order or resolve parameter/result OIDs without executing |
-| Parameters and codecs | `text`, `binary`, `typedNull`, `json`, `array`, `postgresOids`, per-query encoders and decoders | Use safe scalar inference, deterministic PostgreSQL types, or extension-owned OID codecs |
-| Transactions | `transaction`, `OliphauntTransaction.rollback`, transaction `closed` | Reserve the session for a callback and explicitly roll back without a later commit |
-| Raw protocol | database `execProtocolRaw`, `execProtocolRawStream` | Send PostgreSQL protocol bytes as one result or synchronous bounded callback chunks; transaction handles deliberately do not expose this bypass, confirmed callback recovery preserves the original error and session, and execution, transport, or recovery failures poison it |
-| Data movement | `backup` | Create the single supported WASIX physical archive |
-| Persistence | Implicit operation and transaction publication boundaries | Publish persistent changes before the owning promise settles |
-| Lifecycle | read-only `closed`, `close`, `Symbol.asyncDispose` | Perform one terminal teardown, stop the database, and release provider ownership |
-| Storage | `memory`, plus the `storage/indexed-db`, `storage/opfs`, `storage/node`, `storage/bun`, and `storage/deno` subpaths | Select one host-appropriate storage provider |
-| Query values | `QueryParam`, `QueryResult`, `RawQueryResult`, `QueryField`, `CommandResult`, `ExecResult`, `DescribeResult` | Use decoded or lossless PostgreSQL parameter and result values |
-| Diagnostics | query-scoped `notices`, `PostgresError`, `WasixStorageError` | Distinguish PostgreSQL diagnostics from host persistence failures |
-| Initialization resources | `OpenConfig.seed`, `WasixSeed`, `OpenConfig.icu` | Select independent archive/manifest inputs; new storage runs initdb unless a seed is selected, reopening needs neither, and ICU data remains required for ICU roots |
-| Extensions | `WasixExtensionDescriptor` | Materialize an exact independently packaged WASIX extension and its startup config; run normal database-local `CREATE EXTENSION`/`LOAD` explicitly in app or ORM migrations |
-| Optional tools | `pgDump`, `psql`, `PostgresToolError` from `@oliphaunt/wasix-tools` | Run a standard plain logical dump against root, direct, or Worker handles; non-interactive psql accepts any native-host placement and requires a Worker handle in browsers |
-| Optional local server | `openServer`, `ServerListen`, `OliphauntServer.connectionString`, read-only `OliphauntServer.closed`, `close`, and `Symbol.asyncDispose` from `@oliphaunt/wasix-ts/server` | Publish and lifecycle-manage one loopback TCP or PostgreSQL-named Unix endpoint on Node, Bun, Deno, or Electron |
-
-```ts
-const result = await database.query('select $1::int4 as answer', [41]);
-const answer = result.rows[0]?.answer;
-const raw = await database.queryRaw('select $1::bytea as payload', [new Uint8Array([1, 2])]);
-```
-
-The cross-SDK behavior follows the
-[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md).
-
-Inside a callback transaction, do not issue manual `BEGIN`, `START
-TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`.
-Use callback return/throw or `rollback()`; `SAVEPOINT` and `ROLLBACK TO` are
-supported. `ROLLBACK AND CHAIN` is unsupported and wire-indistinguishable from
-`ROLLBACK TO`, so Oliphaunt rejects `ROLLBACK`/`ABORT ... AND CHAIN` before
-dispatch and enforces every other ownership boundary from PostgreSQL response
-frames. A proven escape makes the database close-only and suppresses any
-follow-up SDK transaction command.
-
-After rollback and required persistence publication succeed, the original
-callback failure is rethrown unchanged. If rollback also fails, an
-`AggregateError` contains the callback failure followed by the rollback failure.
-If the callback throws a different value after an earlier independent database
-or protocol failure poisoned or expired ownership, an `AggregateError` contains
-the callback failure followed by that database failure and the database is
-close-only. Ordinary PostgreSQL statement errors that remain safely rollbackable
-do not automatically produce an aggregate.
-
-WASIX `close()` has one memoized terminal outcome. It stops admission as soon
-as close begins and lets already accepted database work finish. The root actor
-drains its Rust owner, `/direct` closes on its owning thread, and `/worker`
-closes at quiescence, posts its reply, then exits itself without terminating an
-active Node-API frame. A
-rejected close still leaves `closed === true`; repeat calls return the same
-rejected promise rather than claiming the destroyed session can be retried.
-Provider close and allocation release are attempted before that rejection is
-reported. A close call made from the active transaction callback rejects before
-teardown begins and leaves the database open; call it again after the callback
-settles.
-
-An unexpected package-Worker failure also makes `closed === true` immediately.
-Later operations fail locally instead of posting to the terminal transport.
-`close()` remains idempotent and reports that transport failure while finishing
-any remaining package-owned cleanup.
-
-A raw-stream callback cannot return a thenable or reenter the same database or
-transaction. Its original error is surfaced only after the runtime confirms a
-known recovered protocol boundary, leaving the database reusable. A buffered
-raw rejection or streamed execution, transport, or recovery failure is
-authoritative instead, poisons the database, and is never masked by a callback
-error.
-
-An unreachable database handle has generation-guarded best-effort cleanup. It
-can retire only its own actor, direct guest/storage lease, or Worker, and a stale
-finalizer is a no-op. This is a leak-safety fallback, not a prompt lifecycle
-boundary; use `close()` or `await using` whenever teardown must be observed.
-
-The public API has no backup-format enum, capability object, initialization
-profile, replace policy, runtime fallback, cancellation, or dedicated COPY
-streaming mode. Server and tool support is deliberately absent from the core
-database object and exposed only through the optional surfaces above. These are
-fixed semantics rather than configuration switches.
+`@oliphaunt/wasix-ts` exports `Oliphaunt` and its TypeScript declarations. The default export is the same client.
+
+## Entry points
+
+| Import | Exports / purpose |
+| --- | --- |
+| Package root | `Oliphaunt.open`, `Oliphaunt.restore`, query types and helpers |
+| `/direct` | Desktop-only caller-thread placement |
+| `/worker` | Worker placement with the same query contract |
+| `/server` | Desktop-only `openServer` |
+| `/storage/indexed-db`, `/storage/opfs` | Browser persistent providers |
+| `/storage/node`, `/storage/bun`, `/storage/deno` | Desktop directory providers |
+
+`open(config?)` returns `Promise`. `restore(storage, bytes)` returns `Promise` and requires a `PersistentWasixStorage` destination.
+
+## Configuration
+
+| Field | Type / default |
+| --- | --- |
+| `storage` | `WasixStorage`; fresh memory filesystem |
+| `extensions` | `readonly WasixExtensionDescriptor[]`; empty |
+| `startupGUCs` | `Record`; no extra settings |
+| `username`, `database` | Optional strings; fresh roots use `postgres` |
+| `icu` | Optional imported `WasixIcuDescriptor` |
+| `seed` | Optional `WasixSeed`; initializes fresh storage |
+
+Extension descriptors come from `@oliphaunt/extension-*-wasix` packages. SQL-name strings are not accepted. Host placement is selected by import, not an `execution` configuration option.
+
+## Queries and transactions
+
+`query`, `execute`, `queryRaw`, `exec`, and `describe` provide typed queries, command metadata, raw column values, multiple statements, and statement metadata. They accept positional parameters and appropriate query options. Typed rows are buffered.
+
+`transaction(body)` owns one session until settlement. Returning commits; throwing rolls back. The transaction handle exposes typed query methods and `rollback()`, and expires after use. Raw protocol and backup belong only to the database. Manual outer transaction-lifecycle SQL is unsupported; savepoints are supported.
+
+## Persistence and close
+
+`backup()` returns `Promise`. Persistent operations settle only after required provider publication. Restore validates archive compatibility and rejects nonempty destinations.
+
+`close()` returns `Promise` and performs one terminal teardown attempt. `closed` reports terminal state, including unexpected isolated-host termination. Repeated close calls share the same result. `Symbol.asyncDispose` uses the same close operation.
+
+There is no public direct-query `cancel()` method. Browser TCP listeners and independent endpoint sessions are unavailable.
+
+## Protocol and errors
+
+`execProtocolRaw` returns buffered backend bytes. `execProtocolRawStream` accepts a synchronous callback returning `undefined`. The callback is a backpressure boundary and cannot return a promise or re-enter the same database.
+
+`PostgresError` contains SQLSTATE and backend diagnostics. A recovered callback failure can leave a session usable; transport, recovery, or persistence-publication failure can make it close-only. Composite transaction failures retain both relevant causes.
+
+See the [guide](/docs/sdk/wasix-typescript/guide) for tools, storage examples, and host requirements.
diff --git a/src/docs/content/sdk/wasix-typescript/guide.mdx b/src/docs/content/sdk/wasix-typescript/guide.mdx
index 9bdcee811..d666c93b7 100644
--- a/src/docs/content/sdk/wasix-typescript/guide.mdx
+++ b/src/docs/content/sdk/wasix-typescript/guide.mdx
@@ -1,328 +1,143 @@
---
-title: Build With WASIX TypeScript
-description: Open, persist, transact, back up, and restore portable PostgreSQL from TypeScript.
+title: WASIX TypeScript guide
+description: Choose storage and execution placement, transact, back up, and use PostgreSQL tools.
---
-# Build With WASIX TypeScript
+These recipes build on the [WASIX TypeScript quickstart](/docs/sdk/wasix-typescript). An open `db` owns one PostgreSQL session.
-
-The resource and package separation shown below is unreleased. Installation
-versions on this site come from completed public releases; they do not make the
-new seed, resource, or pgwire packages available. Use a coordinated source
-checkout for these examples until those products are published.
-
+## Choose persistent storage
-
+Import only the adapter for your host:
-
-
+| Host | Import | Create storage |
+| --- | --- | --- |
+| Browser IndexedDB | `@oliphaunt/wasix-ts/storage/indexed-db` | `indexedDB('notes')` |
+| Browser OPFS | `@oliphaunt/wasix-ts/storage/opfs` | `opfs('notes')` |
+| Node.js / Electron | `@oliphaunt/wasix-ts/storage/node` | `directory('./data/notes')` |
+| Bun | `@oliphaunt/wasix-ts/storage/bun` | `directory('./data/notes')` |
+| Deno | `@oliphaunt/wasix-ts/storage/deno` | `directory('./data/notes')` |
-### Install
-
-Install the same package for browsers, Node.js, Bun, Deno, and Electron:
-
-```sh
-bun add @oliphaunt/wasix-ts@{{release:oliphaunt-wasix-ts}}
-```
-
-Deno uses the same npm package as browsers, Node.js, Bun, and Electron:
-
-```ts
-import Oliphaunt from 'npm:@oliphaunt/wasix-ts';
-import { directory } from 'npm:@oliphaunt/wasix-ts/storage/deno';
-```
-
-Use local `node_modules` resolution and grant `--allow-ffi`, `--allow-read`, and
-`--allow-env`; `/worker` does not require process-spawn permission. Configure
-Electron packagers to leave `**/prebuilds/**` unpacked and ship
-`app.asar.unpacked` beside `app.asar`, keeping the addon and platform loader
-companions in one directory.
-
-
-
-
-### Open and query
+For example, a Node.js application opens a persistent root with:
```ts
import Oliphaunt from '@oliphaunt/wasix-ts';
-import archive from '@oliphaunt/seed-wasix-standard/seed.tar.zst?url';
-import manifest from '@oliphaunt/seed-wasix-standard/manifest.json?url';
-
-const seed = { archive, manifest };
-await using database = await Oliphaunt.open({ seed });
-const result = await database.query('select $1::int + 1 as answer', [41]);
-console.log(result.rows[0]?.answer);
-```
-
-New browser storage runs the runtime's initdb when no seed is selected.
-The optional seed imports above use a browser bundler's asset URL support;
-seed packages are independently installed development
-carriers, not part of the SDK. Existing IndexedDB or OPFS storage reopens without
-`seed`. Node/Bun/Deno can initialize without a seed using the runtime's initdb.
-
-For ICU, pass
-`icu: { data, manifest }`, where `data` is the raw `@oliphaunt/icu/data`
-asset and `manifest` is `@oliphaunt/icu/manifest`. Load both with `?url`
-in a browser bundler, or pass their bytes on a native host. ICU data remains
-required when reopening an ICU database; the seed does not. If selecting a seed, use `@oliphaunt/seed-wasix-icu`.
-
-Browser pages must send these response headers. Bundlers using the explicit
-Worker surface must also preserve its module Worker asset:
+import { directory } from '@oliphaunt/wasix-ts/storage/node';
-```text
-Cross-Origin-Opener-Policy: same-origin
-Cross-Origin-Embedder-Policy: require-corp
+const db = await Oliphaunt.open({ storage: directory('./data/notes') });
```
-
-
+Only one live owner may use a persistent root or browser storage name. Close the current handle before opening it from another Worker, process, or binding.
-### Create app data
+## Choose execution placement
-Use ordinary PostgreSQL SQL and parameters. `query()` returns rows;
-`execute()` returns the PostgreSQL command result.
+| Import | Browser | Desktop host |
+| --- | --- | --- |
+| `@oliphaunt/wasix-ts` | Executes in the importing realm | Dedicated Rust owner keeps the event loop responsive |
+| `@oliphaunt/wasix-ts/direct` | Unavailable | May block the calling JavaScript thread |
+| `@oliphaunt/wasix-ts/worker` | Package-owned Worker | Package-owned JavaScript Worker |
-```ts
-await database.execute(
- 'create table if not exists note (id bigserial primary key, title text not null)',
-);
-await database.execute('insert into note(title) values ($1)', ['First note']);
-const notes = await database.query('select id, title from note order by id');
-```
-
-Use `transaction(async tx => …)` for one callback-scoped transaction. Calls on
-the database handle do not interleave with the callback; use the `tx` handle
-inside it.
-
-A callback failure is rethrown unchanged after rollback and required persistence
-publication succeed. If rollback also fails, `AggregateError.errors` contains
-the callback failure followed by the rollback failure. If the callback throws a
-different value after an earlier independent database or protocol failure
-poisoned or expired transaction ownership, the aggregate instead contains the
-callback failure followed by that database failure and the database is
-close-only. Ordinary PostgreSQL statement errors that remain safely rollbackable
-do not automatically produce an aggregate.
+The available placements return the same promise-based query API. An async signature alone does not mean that execution is off the calling thread. Use `/worker` in a browser UI that must remain responsive.
-
-
+OPFS uses synchronous file access where the browser provides it in a Dedicated Worker. In a Window or a host without those handles, the adapter uses its portable persistence path automatically.
-### Configure
-
-Memory is the default. Persistent storage is an explicit selective import:
+## Query and transact
```ts
-import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db';
-// Or: storage/opfs in browsers; storage/node, storage/bun, or storage/deno on servers.
-
-const database = await Oliphaunt.open({
- storage: indexedDB('notes'),
- seed,
- startupGUCs: { application_name: 'notes' },
+await db.execute('CREATE TABLE IF NOT EXISTS notes (body text NOT NULL)');
+await db.transaction(async (tx) => {
+ await tx.execute('INSERT INTO notes (body) VALUES ($1)', ['First']);
+ await tx.execute('INSERT INTO notes (body) VALUES ($1)', ['Second']);
});
+console.log((await db.query('SELECT body FROM notes')).rows);
```
-IndexedDB and OPFS names are origin-owned identities. Host-runtime directory
-adapters take a managed-root path containing `.oliphaunt.json` and `pgdata`.
-The Rust WASIX runtime's stable sibling advisory lock is outside that root and
-is not backup content. It coordinates Rust WASIX and native-host TypeScript
-owners without adding a public lock protocol. A root must have one live owner;
-close it before another process, Worker, or binding opens the same path.
+Return to commit and throw to roll back. Use only the callback's `tx` for its statements. Do not manually begin, end, or replace the outer transaction; use `tx.rollback()` for explicit rollback. Savepoints are supported.
-OPFS uses browser synchronous access handles for exact-range PostgreSQL file
-I/O with the explicit Worker entry point and when the root entry point is
-imported inside an application-owned Dedicated Worker. A root import in a
-browser Window, and hosts without synchronous access handles, use the portable
-journal against the same opaque OPFS format. This selection is automatic and
-adds no public mode or tuning option.
+Persistent operations publish their changes before their promises settle. A transaction publishes after confirmed commit or rollback. If publication fails, the handle becomes unusable: close it and reopen the last complete stored generation. The failed operation may have an uncertain outcome; inspect application state before retrying a write.
-
-
+## Select extensions
-### Choose execution placement
+Install a WASIX extension package and pass its descriptor, not a SQL-name string:
-Use the root normally. In browsers it executes in the importing realm; on
-Node-compatible hosts it uses a dedicated Rust owner and keeps the event loop
-responsive. Import `/direct` when deliberately trading responsiveness for the
-lowest dispatch overhead, or `/worker` for a separate JavaScript realm:
-
-```ts
-import OliphauntWorker from '@oliphaunt/wasix-ts/worker';
-import OliphauntDirect from '@oliphaunt/wasix-ts/direct';
-
-const database = await OliphauntWorker.open({ seed });
+```sh
+npm install @oliphaunt/extension-pgtap-wasix@{{release:oliphaunt-extension-pgtap}}
```
-All placements return the same Promise-shaped `OliphauntDatabase` contract.
-The native root adds one Rust-owner completion hop, `/direct` can block its
-realm, and `/worker` adds a JavaScript RPC hop. There is no runtime fallback,
-capability profile, or host-mode negotiation.
-
-
-
-
-### Handle lifecycle
-
-Ordinary operations publish persistent changes before their promises settle.
-Transactions publish once after confirmed `COMMIT` or `ROLLBACK`.
-An explicit PostgreSQL checkpoint, when operationally required, is ordinary SQL:
-`await database.execute('CHECKPOINT')`. A publication failure poisons the handle
-because PostgreSQL may contain changes not present in the last durable
-generation; close it and reopen the last complete generation.
-
-`close()` begins one terminal teardown attempt and attempts final provider
-publication and ownership release. Concurrent and later calls return the same
-promise. If teardown rejects, the error reports cleanup that could not complete,
-but the handle still becomes `closed` and cannot accept more work: its actor,
-isolated transport, or direct guest has already been retired. `await using` calls
-the same operation through `Symbol.asyncDispose`.
-
-On `/worker`, close stops admission, waits for the active native frame and
-queued work to settle, releases the native handle, and lets the Worker exit
-itself. The package never force-terminates an active Node-API frame. If the
-Worker exits unexpectedly, `closed` becomes `true` as soon as the transport
-observes ownership loss; later operations fail without posting to it. Calling
-`close()` remains useful and idempotent and completes remaining package-owned
-cleanup.
-If the public handle is forgotten instead, an owner-free generation token
-schedules best-effort cleanup for only that browser guest, Rust actor, direct
-session/storage lease, or Worker generation. Stale finalizers cannot affect later opens, but finalization is not
-prompt; explicit close remains required when release must be observed.
-
-Calling database `close()` from inside its active transaction callback is the
-one pre-teardown rejection: the transaction still owns the session, so the
-database remains open and must be closed after the callback settles.
-
-
-
-
-### Select extensions
-
-Import exact WASIX extension descriptors and pass them to `open()`:
-
```ts
import pgtap from '@oliphaunt/extension-pgtap-wasix';
-const database = await Oliphaunt.open({ seed, extensions: [pgtap] });
-await database.execute('CREATE EXTENSION pgtap');
+const db = await Oliphaunt.open({ extensions: [pgtap] });
+await db.execute('CREATE EXTENSION IF NOT EXISTS pgtap');
```
-In browsers, selection materializes only the verified carrier artifacts and
-required startup/preload configuration. On Node.js, Bun, Deno, and Electron,
-the addon embeds the frozen qualified catalog and validates each selected
-descriptor before resolving its SQL name to those exact compiled artifacts.
-Reopen persistent data with the same selection. Neither path silently runs
-`CREATE EXTENSION`, `LOAD`, schema, post-create, upgrade, or migration SQL.
-Applications and ORM migrations own that ordinary PostgreSQL lifecycle.
+Use the same selection when reopening extension-bearing data. The SDK does not run application migrations or `CREATE EXTENSION` automatically. Include the selected extension packages when deploying your app.
-
-
-
-### Back up and restore
-
-`backup()` creates one PostgreSQL 18 WASIX physical archive while preserving the
-open session:
+## Back up and restore
```ts
-const archive = await database.backup();
-await database.close();
-
-import { directory } from '@oliphaunt/wasix-ts/storage/node';
+const archive = await db.backup();
+await db.close();
await Oliphaunt.restore(directory('./data/restored'), archive);
+const restored = await Oliphaunt.open({ storage: directory('./data/restored') });
+await restored.close();
```
-Restore accepts persistent storage only and requires a new or empty destination.
-It validates the exact WASIX archive identity before publishing. It does not
-replace a nonempty database. The destination creates its own managed-root
-descriptor; `.oliphaunt.json` is not carried in the archive.
-
-
-
+This fragment uses the Node.js `directory` adapter imported above. In a browser, pass a fresh IndexedDB or OPFS storage descriptor instead. Restore requires new or empty persistent storage and a compatible WASIX physical archive. Reapply required extensions when opening restored data.
-### Use PostgreSQL tools
+## Use logical PostgreSQL tools
-The tools package now has its own `postgres-tools-wasix` release owner. Until
-that owner has a completed release, use the checkout carrier for the examples
-below; do not substitute the SDK version. Add it when standard logical SQL is needed:
+Install the optional tools package:
```sh
-bun add @oliphaunt/wasix-tools@{{release:postgres-tools-wasix}}
+npm install @oliphaunt/wasix-tools@{{release:postgres-tools-wasix}}
```
```ts
-import Oliphaunt from '@oliphaunt/wasix-ts';
import OliphauntWorker from '@oliphaunt/wasix-ts/worker';
import { pgDump, psql } from '@oliphaunt/wasix-tools';
-await using source = await Oliphaunt.open({ seed });
-const sql = await pgDump(source, { args: ['--schema-only'] });
-await using target = await OliphauntWorker.open({ seed });
-await psql(target, { script: sql });
+const sql = await pgDump(db);
+const target = await OliphauntWorker.open();
+try {
+ await psql(target, { script: sql });
+} finally {
+ await target.close();
+}
```
-Tools work in browsers, Node.js, Bun, Deno, and Electron. `pgDump()` accepts a
-root, direct, or Worker handle and returns PostgreSQL's ordinary plain UTF-8 dump,
-including its normal COPY statements. It does not force inserts or rewrite
-valid SQL. `psql()` accepts any handle on Node, Bun, Deno, and Electron; browsers
-require a Worker handle because COPY restore is full duplex. It is included so
-the same standard output can be applied without inventing a second logical
-restore API. Interactive psql, custom archives, parallel jobs, and `pg_restore`
-are outside this minimal tools product.
+`pgDump` supports root, direct, and Worker handles. `psql` supports all desktop placements; in browsers it requires a Worker handle. A plain dump can contain COPY data and psql commands, so restore it with `psql`, not `execute`.
-Tool runs exclusively own and reset the embedded PostgreSQL session. Do not
-expect raw-protocol prepared statements or session settings to survive a tool
-run.
+Tools exclusively use and reset the session. Reapply session settings and prepared statements after a tool run. Interactive psql, custom archives, parallel jobs, and `pg_restore` are outside this tools API.
-
-
+## Open a local endpoint
-### Open a local endpoint
-
-Node, Bun, Deno, and Electron may expose the single embedded backend through an explicit
-host subpath:
+On Node.js, Bun, Deno, or Electron, use the `/server` entry point:
```ts
import { openServer } from '@oliphaunt/wasix-ts/server';
-import { directory } from '@oliphaunt/wasix-ts/storage/node';
-await using server = await openServer({
+const server = await openServer({
storage: directory('./data/server'),
listen: { transport: 'tcp' },
});
console.log(server.connectionString);
+// Close the PostgreSQL client before awaiting server.close().
```
-The same `/server` import works on Node, Bun, Deno, and Electron. TCP is IPv4
-loopback-only; omitting the port chooses an available port. Unix hosts may use
-`{ transport: 'unix', directory, port? }`, which creates
-`.s.PGSQL.`. The compatibility endpoint serves one active client at a
-time. An additional connection is not deterministically rejected and may wait
-in the operating system's listen backlog, so configure a client pool with
-`max: 1`. Each served client receives a fresh embedded backend while the
-listener and storage lease remain open. The endpoint is absent in browsers and
-is not the concurrent WASIX postmaster.
-`server.closed` is read-only: it stays `false` while terminal teardown is in
-progress and becomes `true` after the memoized close attempt settles, even when
-that attempt rejects.
-
-
-
-
-
-
-## Troubleshooting
-
-SQL failures are `PostgresError` values and include PostgreSQL fields such as
-`sqlstate`. A recovered SQL error does not poison the database. Provider load,
-ownership, compatibility, restore, or publication failures are
-`WasixStorageError` values; inspect `code` and `commitState`. A browser open
-failure commonly means the page is not cross-origin isolated or a Worker/runtime
-subresource violates COEP.
-
-Use `execProtocolRawStream(input, callback)` instead of `execProtocolRaw(input)`
-when an adapter expects a large protocol response. The synchronous callback is
-backpressured and receives bounded chunks; it cannot return a Promise/thenable
-or reenter the same database or transaction. A callback error is preserved only
-after confirmed protocol recovery and leaves the database reusable. A buffered
-raw rejection or streamed execution, transport, or recovery failure poisons the
-database and takes precedence over the callback outcome. Typed query results
-remain buffered.
+The endpoint accepts **one connected client at a time**. Configure a client pool with a maximum of one connection. Browser apps cannot use this TCP endpoint. Choose a native server when independent sessions are required.
+
+## Desktop host setup
+
+Deno needs local npm module resolution. Set `"nodeModulesDir": "auto"` in `deno.json`, use `npm:` import prefixes, and grant native loading and storage permissions:
+
+```sh
+deno run --allow-ffi --allow-read --allow-write --allow-env main.ts
+```
+
+The Worker placement does not require process-spawn permission. Electron packaging must leave `**/prebuilds/**` unpacked and preserve native loader companions beside the addon in `app.asar.unpacked`.
+
+## Errors and shutdown
+
+Handle SQL failures using `PostgresError` and SQLSTATE. Transaction aggregates preserve callback and rollback/database failures. Await `close()` to observe cleanup; even a failed teardown makes the handle terminal. Close after a transaction callback settles, not from inside it.
+
+There is no public direct-query cancellation API. Keep transactions and queries bounded, and select an execution placement that preserves application responsiveness.
diff --git a/src/docs/content/sdk/wasix-typescript/index.mdx b/src/docs/content/sdk/wasix-typescript/index.mdx
index 82a9955e3..f515b593d 100644
--- a/src/docs/content/sdk/wasix-typescript/index.mdx
+++ b/src/docs/content/sdk/wasix-typescript/index.mdx
@@ -1,79 +1,64 @@
---
title: WASIX TypeScript SDK
-description: Run portable PostgreSQL in browsers, Node.js, Bun, Deno, and Electron with one small asynchronous API.
+description: Run PostgreSQL as WebAssembly in browsers and desktop JavaScript runtimes.
---
-> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases.
+Use `@oliphaunt/wasix-ts` in browsers, Node.js, Bun, Deno, or Electron. It runs the WASIX PostgreSQL runtime. For native desktop PostgreSQL, use the separate [TypeScript SDK](/docs/sdk/typescript).
+## Install
+Desktop requirements are Node.js 22.13 through 24.x, Bun 1.3.14+, or Deno 2.8.1+.
-# WASIX TypeScript SDK
+```sh
+npm install @oliphaunt/wasix-ts@{{release:oliphaunt-wasix-ts}}
+```
-
+Deno imports the same package with `npm:@oliphaunt/wasix-ts@{{release:oliphaunt-wasix-ts}}`; see [host setup](/docs/sdk/wasix-typescript/guide#desktop-host-setup).
-`@oliphaunt/wasix-ts` hosts the portable `liboliphaunt-wasix` runtime in a
-browser, Node.js, Bun, Deno, or Electron. It is a separate product from native
-`@oliphaunt/ts`: neither package selects or falls back to the other.
+## Prepare a browser app
-## Install
+Serve the application with these HTTP response headers:
-```sh
-bun add @oliphaunt/wasix-ts@{{release:oliphaunt-wasix-ts}}
+```text
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
```
-Deno uses the same npm package through an `npm:` import.
+Check that `window.crossOriginIsolated` is `true`. Serve all runtime and Worker assets with compatible cross-origin policies. Configure your bundler to preserve the package's module Worker asset when using `/worker`.
+
+Desktop runtimes do not need these browser headers.
+
+## Run your first query
+
+The root import works across hosts. In a browser it runs in the importing realm; use the Worker import shown below when database execution must stay off the UI thread.
-## Open And Query
+
```ts
import Oliphaunt from '@oliphaunt/wasix-ts';
-await using database = await Oliphaunt.open();
-const result = await database.query('select $1::int + 1 as answer', [41]);
-console.log(result.rows[0]?.answer);
+const db = await Oliphaunt.open();
+try {
+ const result = await db.query('SELECT $1::int4 AS answer', [42]);
+ console.log(result.rows[0]?.answer); // 42
+} finally {
+ await db.close();
+}
```
-Omitted storage creates a fresh in-memory database. Browser pages must be
-cross-origin isolated with COOP `same-origin` and COEP `require-corp`.
-
-## Runtime Shape
-
-In browsers the root runs the database in the importing JavaScript realm. On
-Node-compatible hosts the root uses a dedicated Rust owner and keeps the event
-loop responsive. `@oliphaunt/wasix-ts/direct` opts into the lowest-overhead
-blocking native placement, while `@oliphaunt/wasix-ts/worker` uses a
-package-owned JavaScript Worker on every runtime. There is no `execution`
-option or silent placement fallback.
-
-The core package provides queries, commands, callback transactions, buffered
-and callback-streamed raw PostgreSQL protocol bytes, one physical backup,
-restore into persistent storage, and close. Optional
-`@oliphaunt/wasix-tools` adds `pgDump` for root, direct, or Worker handles.
-Non-interactive `psql` works with all three placements on Node, Bun, Deno, and Electron; browsers
-require a Worker handle. The host-only `/server` subpath adds a local endpoint
-on Node, Bun, Deno, and Electron. Cancellation and a dedicated typed COPY API remain
-absent.
-
-## App Responsibilities
-
-- New browser storage runs initdb; an independent seed can skip that work.
- Reopening existing storage needs no seed; ICU roots still need their ICU data.
-
-- Import only the persistent-storage adapter and exact WASIX extension packages
- the application uses.
-- Keep the same extension selection when reopening a persistent database.
-- Call `close()` or use `await using`. If an operational workflow explicitly
- requires PostgreSQL `CHECKPOINT`, issue it through `execute('CHECKPOINT')`.
-- Treat physical archives as same-format recovery artifacts. Use logical SQL
- dumps for version upgrades or transfers outside the WASIX physical format.
-- Use root, direct, or Worker handles for `pgDump`. On Node, Bun, Deno, and Electron,
- all three placements also support `psql`; browsers require a Worker handle.
- Use the lightweight local endpoint for one compatibility client, or the
- separate postmaster product for concurrency.
-
-## First Query
-
-Use the [guide](/docs/sdk/wasix-typescript/guide) for storage, transactions,
-backup, restore, tools, and local endpoints. Use the [API reference](/docs/sdk/wasix-typescript/api-reference)
-for the exact exported declarations. Rust hosts use the separate
-[Rust WASIX SDK](/docs/sdk/wasix-rust).
+The default database lives in memory and is discarded on close.
+
+## Keep browser data between sessions
+
+Use IndexedDB and run the database in a Worker:
+
+```ts
+import OliphauntWorker from '@oliphaunt/wasix-ts/worker';
+import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db';
+
+const db = await OliphauntWorker.open({ storage: indexedDB('notes') });
+```
+
+Reopen the same name from the same origin to access saved data. Browser storage remains subject to browser quotas and user data-clearing policies. Keep the handle in application state and close it when finished.
+
+For OPFS, desktop directories, transactions, and data export, continue with the [WASIX TypeScript guide](/docs/sdk/wasix-typescript/guide). Use the [API reference](/docs/sdk/wasix-typescript/api-reference) for import paths and methods.
diff --git a/src/docs/content/start/index.mdx b/src/docs/content/start/index.mdx
index ce9ebfefc..cbb372082 100644
--- a/src/docs/content/start/index.mdx
+++ b/src/docs/content/start/index.mdx
@@ -1,37 +1,19 @@
---
-sidebar_position: 1
-title: Start With Oliphaunt
-description: Choose an Oliphaunt SDK, open embedded PostgreSQL storage, and run the first query.
+title: Get started
+description: Run PostgreSQL inside your app, without a separate database service.
---
-Oliphaunt is embedded PostgreSQL for apps. Install the SDK for your runtime
-owner, open with its sensible storage default, run SQL, and select only the
-extensions your app ships. Native, Rust WASIX, and WASIX TypeScript are
-separate product choices.
+## Choose your SDK
-This page is the shortest tutorial path. Pick one app target, prove the runtime
-with one query, then move into the SDK, runtime, extension, or storage page that
-matches the next decision.
+
-## Start In One App Target
+Start with the native SDK for your app's platform. For a browser app, use **WASIX TypeScript**. WASIX runs PostgreSQL as WebAssembly and also has a Rust binding.
-
+Each quickstart includes installation, a complete query example, and persistent storage setup. Compare [runtime support](/docs/reference/capabilities) if you need process isolation, an ORM, or browser storage.
-## First Query Shape
+## After your first query
-Every SDK uses ecosystem-native syntax. The application flow stays the same:
-choose the runtime product and storage, select exact extensions, open, query,
-and close.
-
-
-
-Use the SDK page for your app target when you need platform setup, native build
-consequences, app-owned cancel/close behavior, PostgreSQL maintenance SQL,
-extension artifacts, backup, restore, and troubleshooting.
-
-## After The First Query
-
-Use these pages when the first runtime path works and the app needs the next
-production decision.
-
-
+- **Build application features.** Your SDK's guide covers parameters, transactions, backups, and errors.
+- **Understand storage.** [Embedded PostgreSQL](/docs/learn/embedded-postgres) explains database lifetime and recovery.
+- **Add PostgreSQL extensions.** [Choose an extension](/docs/reference/extensions), then follow your SDK's setup.
+- **Bring an existing app.** Read [Moving from SQLite](/docs/learn/sqlite-upgrade) or [Use with Tauri](/docs/learn/tauri).
diff --git a/src/docs/docs-manifest.toml b/src/docs/docs-manifest.toml
index b89a1dd6c..61e15a695 100644
--- a/src/docs/docs-manifest.toml
+++ b/src/docs/docs-manifest.toml
@@ -51,12 +51,6 @@ page_order = [
"extension-catalog",
"api-reference",
]
-sidebar_pages = [
- "index",
- "capabilities",
- "extensions",
- "performance",
-]
[[routes]]
id = "oliphaunt-rust"
@@ -75,10 +69,6 @@ page_order = [
"guide",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
-]
[[routes]]
id = "oliphaunt-swift"
@@ -97,10 +87,6 @@ page_order = [
"guide",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
-]
[[routes]]
id = "oliphaunt-kotlin"
@@ -119,10 +105,6 @@ page_order = [
"guide",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
-]
[[routes]]
id = "oliphaunt-react-native"
@@ -142,11 +124,6 @@ page_order = [
"architecture",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
- "architecture",
-]
[[routes]]
id = "oliphaunt-js"
@@ -165,15 +142,11 @@ page_order = [
"guide",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
-]
[[routes]]
id = "oliphaunt-wasix-rust"
product_id = "oliphaunt-wasix-rust"
-title = "Rust WASIX SDK"
+title = "WASIX Rust SDK"
kind = "sdk"
route = "sdk/wasix-rust"
source = "src/docs/content/sdk/wasix-rust"
@@ -189,12 +162,6 @@ page_order = [
"dump-restore",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
- "runtime",
- "dump-restore",
-]
[[routes]]
id = "oliphaunt-wasix-typescript"
@@ -213,10 +180,6 @@ page_order = [
"guide",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
-]
[[routes]]
id = "liboliphaunt-native"
@@ -235,7 +198,3 @@ page_order = [
"guide",
"api-reference",
]
-sidebar_pages = [
- "index",
- "guide",
-]
diff --git a/src/docs/maintainers/README.md b/src/docs/maintainers/README.md
index a029868ac..31c817d1d 100644
--- a/src/docs/maintainers/README.md
+++ b/src/docs/maintainers/README.md
@@ -38,3 +38,5 @@ When changing a workflow or contract:
2. update the relevant maintainer entry point and its verified date;
3. regenerate derived tables instead of hand-editing them;
4. avoid policy assertions that depend on YAML step order, display text, or helper filenames unless the string itself is an external API.
+
+- [Documentation authoring](../README.md) and [current documentation audit](docs-rebase-audit.md).
diff --git a/src/docs/maintainers/docs-rebase-audit.md b/src/docs/maintainers/docs-rebase-audit.md
new file mode 100644
index 000000000..406daee41
--- /dev/null
+++ b/src/docs/maintainers/docs-rebase-audit.md
@@ -0,0 +1,141 @@
+# Documentation rebase audit — 2026-09-29
+
+## Scope and baseline
+
+Rebased PR #205 onto remote `main` at `32ce7b29510b74333e799601b69a71fd28122e80`. Reviewed all **42 authored public pages**, **44 generated documentation routes**, the root README, and seven SDK READMEs. This record supersedes the September 8 audit for the current checkout; historical registry experiments are not evidence for current packages.
+
+The requested target remains the checkout API, treating its versions as published. Completed GitHub releases can lag that target. Examples resolve `{{release:product-id}}` from the existing Release Please config and manifest, while the version table separately links completed releases. The export includes `docs-version.json` with revision, dirty state, and documented product versions. No registry publication or hosted historical version selector is claimed.
+
+Applied `better-writing`: installation and required resources precede a complete query; persistence and application recipes follow; references stay visible. Removed maintainer implementation/design explanations from the developer path while retaining constraints needed for correct use. The updated [local skill](../../../.codex/skills/write-oliphaunt-docs/SKILL.md) records this process.
+
+The primary-source review drew on [Turso quickstarts](https://docs.turso.tech/sdk/ts/quickstart), [PGlite documentation](https://pglite.dev/docs/), [Supabase React setup](https://supabase.com/docs/guides/getting-started/quickstarts/reactjs), and [Motion React docs](https://motion.dev/docs/react). Adapted their early runnable examples, ecosystem entry points, and separation of setup, recipes, and reference; retained Oliphaunt-specific lifecycle and packaging requirements. Details are in the skill's [research notes](../../../.codex/skills/write-oliphaunt-docs/references/research.md).
+
+## Public page ledger
+
+Every file below was read completely and compared with its current API or route source. This is a source review, not a claim that every recipe was executed. Source locations are indexed in the [source map](../../../.codex/skills/write-oliphaunt-docs/references/source-map.md).
+
+| File | Developer task | Findings and disposition | Evidence inspected |
+| --- | --- | --- | --- |
+| [learn/embedded-postgres.mdx](../content/learn/embedded-postgres.mdx) | Understand storage and recovery | Distinguished native process-root lifetime from WASIX lifetime; mobile broker now available. | Native/WASIX storage, direct and broker lifecycle |
+| [learn/index.mdx](../content/learn/index.mdx) | Find application guides | Reviewed all destinations and descriptions; retained task-based cards. | Route manifest and the five application guides |
+| [learn/mobile-stability.mdx](../content/learn/mobile-stability.mdx) | Ship a mobile database | Added Swift, Kotlin, and Expo broker setup, worker-process guard, resource placement, backup/restore, and failure recovery. | Swift broker/templates, Kotlin broker/service, Expo plugin and RN types |
+| [learn/native-runtime.mdx](../content/learn/native-runtime.mdx) | Choose direct, broker, or server | Updated mobile broker support and retained only constraints that affect an application. | Rust/TS modes; Swift/Kotlin/RN broker entry points |
+| [learn/sqlite-upgrade.mdx](../content/learn/sqlite-upgrade.mdx) | Move an existing application | Reviewed schema, parameter, SQL and data-movement guidance; retained the migration sequence. | PostgreSQL SQL semantics and SDK query/storage APIs |
+| [learn/tauri.mdx](../content/learn/tauri.mdx) | Integrate a Rust desktop application | Removed obsolete manual native-resource setup; retained async state, commands, and server ownership. | Rust builder/async/server implementation and Tauri state API |
+| [reference/api-reference.mdx](../content/reference/api-reference.mdx) | Find each SDK API | Replaced generated-artifact narration with SDK, guide, and reference links. | All eight SDK route groups |
+| [reference/capabilities.mdx](../content/reference/capabilities.mdx) | Compare runtime and platform support | Updated mobile broker capabilities; platform requirements remain generated from policy. | SDK exports and platform compatibility policy |
+| [reference/extensions.mdx](../content/reference/extensions.mdx) | Install and enable an extension | Used typed descriptors and per-ecosystem packaging; removed unsupported universal availability claims. | Generated extension surfaces and SDK resolvers |
+| [reference/index.mdx](../content/reference/index.mdx) | Find exact integration details | Kept direct links; versions describe the documentation target. | Reference routes |
+| [reference/performance.mdx](../content/reference/performance.mdx) | Measure an application workload | Kept reproducible measurement advice; removed shared-engine internals and unsupported performance implications. | Native/WASIX owner and query semantics |
+| [reference/releases.mdx](../content/reference/releases.mdx) | Upgrade dependencies and data | Removed obsolete 0.2 defects and build machinery; documented dependency pins, backups, rebuilds and compatibility. | Current SDK fixes, release metadata and backup/restore APIs |
+| [reference/sdk-products.mdx](../content/reference/sdk-products.mdx) | Map languages to packages | Corrected package/family mapping without release-pipeline details. | Release config and package manifests |
+| [sdk/c-abi/api-reference.md](../content/sdk/c-abi/api-reference.md) | Look up C entry points | Added streaming backup/restore and token-bound stream-input lifetime contract. | Current oliphaunt.h declarations and function comments |
+| [sdk/c-abi/guide.mdx](../content/sdk/c-abi/guide.mdx) | Build a language binding | Updated source/header paths; checked terminal close, scheduling and response/error ownership. | C ABI header and native lifecycle implementation |
+| [sdk/c-abi/index.mdx](../content/sdk/c-abi/index.mdx) | Open and query through C | Kept prepared-root prerequisite, matching header/library and protocol-result handling; centralized version. | Current oliphaunt.h and native init/query implementation |
+| [sdk/index.mdx](../content/sdk/index.mdx) | Find the right SDK | Corrected native/WASIX source layout and retained a single chooser. | SDK manifest and SDK entry points |
+| [sdk/kotlin/api-reference.md](../content/sdk/kotlin/api-reference.md) | Look up Kotlin APIs | Corrected extension, ApplicationData storage and broker API descriptions. | Common/Android public types and broker implementation |
+| [sdk/kotlin/guide.mdx](../content/sdk/kotlin/guide.mdx) | Build an Android application | Used typed extension descriptors, matched build selection, and linked broker setup. | Kotlin extension/configuration, query and restore APIs |
+| [sdk/kotlin/index.mdx](../content/sdk/kotlin/index.mdx) | Install and query on Android | Added Gradle seedProfile requirement and kept File-based persistent storage. | Gradle plugin and Android open/storage API |
+| [sdk/react-native/api-reference.md](../content/sdk/react-native/api-reference.md) | Look up React Native APIs | Updated extension types and broker timeouts; separated build topology from runtime configuration. | RN exported types/client and Expo options |
+| [sdk/react-native/architecture.mdx](../content/sdk/react-native/architecture.mdx) | Configure native integration | Rewrote integration steps around app setup; corrected awaited manual iOS staging and Gradle seed profile. | Published plugin/staging script and Android resource plugin |
+| [sdk/react-native/guide.mdx](../content/sdk/react-native/guide.mdx) | Build a React Native application | Corrected descriptor imports and seed/resource selection; linked broker setup and explicit recovery. | RN client, extensions, native adapters and plugin |
+| [sdk/react-native/index.mdx](../content/sdk/react-native/index.mdx) | Install and query on mobile | Added required iOS seed npm dependency and matching Expo build setup. | RN package, seed discovery, Expo plugin and query types |
+| [sdk/rust/api-reference.md](../content/sdk/rust/api-reference.md) | Look up native Rust APIs | Reviewed builder, direct/async/broker/server, result, backup and error contracts; retained accurate reference. | Rust public exports, builders, error and result types |
+| [sdk/rust/guide.mdx](../content/sdk/rust/guide.mdx) | Build a native Rust application | Selected vector through its extension crate; checked broker restore, transactions and server lifetime. | Rust extension/config, database, session and server APIs |
+| [sdk/rust/index.mdx](../content/sdk/rust/index.mdx) | Install and query native PostgreSQL | Removed obsolete runtime archive/environment workaround; corrected temporary-storage lifetime. | Native Rust builder, resources and public query API |
+| [sdk/swift/api-reference.md](../content/sdk/swift/api-reference.md) | Look up Swift APIs | Added broker entry point/configuration and corrected resource/extension options. | Swift public actor, broker and configuration types |
+| [sdk/swift/guide.mdx](../content/sdk/swift/guide.mdx) | Build an Apple application | Corrected typed extension/resource selection and Bun generator path; linked mobile broker setup. | Swift extension generator, actor transactions and backup/restore |
+| [sdk/swift/index.mdx](../content/sdk/swift/index.mdx) | Install and query on Apple platforms | Added required iOS seed package/product; kept macOS initialization distinction. | Swift Package generation, runtime resource discovery and actor API |
+| [sdk/typescript/api-reference.md](../content/sdk/typescript/api-reference.md) | Look up JavaScript APIs | Corrected NativeExtension[], restore storage, seed and ICU options. | TS exports and declared types |
+| [sdk/typescript/guide.mdx](../content/sdk/typescript/guide.mdx) | Build a desktop JavaScript application | Changed extension selection to descriptors and restore to a DirectoryStorage object; checked broker/server use. | TS config/client, extensions, storage and server provider |
+| [sdk/typescript/index.mdx](../content/sdk/typescript/index.mdx) | Install and query from JavaScript | Removed obsolete Linux release warning; added runnable file command and Deno --allow-run for initdb. | Package exports/engines, client and Deno native adapter |
+| [sdk/wasix-rust/api-reference.md](../content/sdk/wasix-rust/api-reference.md) | Look up WASIX Rust APIs | Corrected server crate ownership and extension package references. | WASIX exports and separate pgwire server crate |
+| [sdk/wasix-rust/dump-restore.mdx](../content/sdk/wasix-rust/dump-restore.mdx) | Export and restore data | Updated optional tools product token; retained physical/logical format distinctions and CLI behavior. | WASIX tools, PgDumpOptions and CLI source |
+| [sdk/wasix-rust/guide.mdx](../content/sdk/wasix-rust/guide.mdx) | Build a WASIX Rust application | Used extension crate with WASIX feature; checked transactions, physical backup and async owner. | WASIX extension declarations, owner and database APIs |
+| [sdk/wasix-rust/index.mdx](../content/sdk/wasix-rust/index.mdx) | Install and query WebAssembly PostgreSQL | Reviewed memory and directory storage, query example and thread ownership; centralized version. | WASIX Rust exports/builder/storage |
+| [sdk/wasix-rust/runtime.mdx](../content/sdk/wasix-rust/runtime.mdx) | Choose execution and server placement | Moved server example to oliphaunt-pgwire-server; removed shared-engine implementation detail. | Pgwire server crate and WASIX owner/storage APIs |
+| [sdk/wasix-typescript/api-reference.md](../content/sdk/wasix-typescript/api-reference.md) | Look up WASIX JavaScript APIs | Corrected desktop-only direct import and WasixSeed type name. | WASIX TS export map and types |
+| [sdk/wasix-typescript/guide.mdx](../content/sdk/wasix-typescript/guide.mdx) | Build a WASIX JavaScript application | Limited /direct to desktop; removed blanket compiled-extension availability; checked host setup and tools. | Host adapters, storage, extensions and tools package |
+| [sdk/wasix-typescript/index.mdx](../content/sdk/wasix-typescript/index.mdx) | Install and query in browsers or desktop JS | Reviewed browser isolation, root/Worker import, IndexedDB persistence and independent version. | WASIX TS package exports, worker and browser storage |
+| [start/index.mdx](../content/start/index.mdx) | Choose an ecosystem and run a query | Kept the eight SDK links and short next-task list; no implementation overview. | SDK manifest, package exports, all quickstarts |
+
+## Generated pages and README review
+
+- `reference/version-matrix`: documented versions and completed releases are distinct columns. A unit test prevents older completed releases from selecting example versions.
+- `reference/extension-catalog`: generated SQL names, activation and upstream versions remain authoritative; removed misleading availability prose.
+- One sidebar exposes all SDK quickstarts, guides and API references, plus shared guides and version lookup. Existing URLs remain intact.
+- The root README now links to the relocated assets and maintainer index.
+- Native Rust and TypeScript READMEs no longer prescribe superseded runtime workarounds or release defects.
+- Swift and Kotlin READMEs link to canonical installation instructions instead of maintaining unsynchronized exact version pins; their first-query and storage examples were reviewed against current types.
+- React Native README includes the seed dependency required by the quickstart.
+- WASIX Rust and TypeScript READMEs were reviewed against current exports and lifetime/storage behavior; no additional content change was needed.
+- The docs README explains authoring, centralized versions, generated platform requirements and static snapshots. Main's Bun toolchain and release-refresh mechanism remain in place.
+- Removed the duplicate generator that overwrote Next's Markdown exports. Expanded SDK links and resolved versions now survive publication.
+- Complete TypeScript quickstarts are source-type-checked during the production build as well as the explicit docs check.
+- Ported the prior branch's docs-only release-selection fix to main's renamed release planner. Markdown changes no longer imply an SDK release through directory ownership; declared changelogs and explicitly mapped release inputs still do. The regression test fails before the fix and passes afterward, including mixed documentation/source changes.
+
+## Verification
+
+| Check | Result and boundary |
+| --- | --- |
+| Frozen Bun installation | Passed; no new dependency. Removed the obsolete direct Motion dependency. |
+| Docs check | Passed: routes, metadata, source links, MDX/site types, version resolution and three TypeScript quickstarts. |
+| Docs tests | Passed: completed-release selection, documented-version selection, live-version verifier and refresh failure handling. |
+| Production build and smoke | Passed: 44 documentation routes, 49 HTML files, internal links/anchors, static assets, all routes in Markdown exports, version snapshot and a real Orama backup query. |
+| Moon docs format and lint | Passed using repository-pinned Moon 2.5.4. |
+| Platform compatibility policy tests | Three passed; no platform floor or support value changed. |
+| Skill validator and diff whitespace check | Passed. |
+| Native Rust first-query example | Compiled as an external consumer against current source; not executed. |
+| WASIX Rust first-query example | Compiled as an external consumer against current source; not executed. |
+| C first-query example | Strict C11 syntax check with warnings as errors against the current header; not linked or executed. |
+| Native TS, WASIX TS, RN first-query examples | Strict type-checks against source; not runtime execution. |
+| Swift, Kotlin, Tauri and native mobile packaging | Source-reviewed; no device, simulator, app package or runtime qualification in this pass. |
+
+The docs build cannot prove that an untested SDK release works on every host. In particular, removing obsolete defect notices follows the fixes present on main, not new cross-platform registry execution.
+
+## Visual review
+
+Reviewed production screenshots at desktop width in light and dark themes and at 390px mobile width. All 44 routes passed a 320px viewport audit: one H1 per page, no page-level horizontal overflow, no unresolved version tokens and no JavaScript errors. Code blocks and tables scroll within the article.
+
+Browser interactions passed: arrow-key installation tabs, code copying with resolved versions, Copy Markdown, Ctrl+K search and navigation to the Rust API result, and opening the mobile sidebar. Clipboard checks required the isolated test browser's clipboard permissions; no site change was needed.
+
+Artifacts remain outside the repository under the thread's visualization directory in `docs-rebase/`: `desktop.png`, `typescript-dark.png`, `swift-mobile.png`, and `layout-audit.json`.
+
+## Visual refinement — 2026-09-29
+
+Inspected the live pages and repository styles for f0rr0.dev, GPU Postal and mealprep.party. The [design grounding](../DESIGN_GROUNDING.md) now records their influence: a neutral dark default, DM Sans reading text, restrained Instrument Serif headings, Geist Mono code, thin dividers and an 8px spacing rhythm. SDK cards became open rows; the start header carries a small static dithered elephant. Removed the repeated introduction so SDK selection comes earlier. No dependency was added.
+
+Replaced an unused legacy Fumadocs width variable with an actual 800px article constraint. Added a first-tab skip link and a main landmark to the shared docs layout. Both themes retain visible focus and reduced-motion support.
+
+| Check | Result and boundary |
+| --- | --- |
+| Moon docs format, lint, check and test-package | Passed; 44 routes and 49 exported HTML files. |
+| All routes at 320px | Passed: one H1 and main landmark, no horizontal page overflow, no unresolved versions. |
+| Seven screenshot and axe samples | Start, TypeScript quickstart, Rust reference, version table, mobile, light theme, and 720×540 CSS viewport at DPR 2 (200% reflow equivalent). No WCAG A/AA violations in these page samples. |
+| Default theme | A fresh visit with a light OS preference starts dark; an explicit light choice persists after reload. |
+| Browser interactions | Skip link, installation tabs, code copy, Markdown copy, search, mobile sidebar toggle and theme toggle checked by keyboard where applicable. Clipboard grants were configured in the isolated browser. |
+| Assistive technology | Accessible roles/names inspected in Chrome; full NVDA/VoiceOver testing and physical-device zoom were not performed. |
+
+Contrast was calculated from rendered foreground/background pairs on the TypeScript quickstart, including composed background colors. Body text measured 16.13:1 dark / 17.18:1 light; muted text 7.49:1 / 5.84:1; inactive tabs 6.15:1 / 5.35:1; the lowest visible syntax-token contrast was 5.72:1 / 4.57:1. These text pairs meet WCAG AA.
+
+The separately opened search dialog retains an upstream Fumadocs 16.9.3 warning: result buttons have `aria-selected` without a supporting role. This is a medium-severity semantic issue, distinct from the passing page samples; keyboard search works. Changing the dependency's search implementation is outside this visual iteration. Do not describe the entire site as accessibility-certified.
+
+Screenshots, reference captures and measurements are in the thread visualization directory under `docs-style/`, including `start.png`, `typescript.png`, `mobile.png`, `light.png`, `reference.png`, `table.png`, `zoom.png`, and `style-audit.json`.
+
+## Identity and spacing refinement — 2026-09-29
+
+Replaced the outlined elephant logo and the small SVG mascot after visual review. Compared three geometric marks at 16, 24, 32 and 128px, in both themes; selected the open O with a curved terminal. The navigation wordmark is now compact lowercase DM Sans. The favicon uses the same path and follows the browser's color scheme. Social cards use the mark, neutral palette and aligned content instead of Fumadocs' default purple treatment.
+
+Page titles alone use Instrument Serif. Section headings use DM Sans. The layout now has explicit 256/768/224px columns, 32px desktop article gutters, a shared leading edge for metadata and content, 24px text line spacing, 16px paragraph spacing, and 48px section spacing. SDK names no longer sit behind a separate icon column. Their rows include the divider in the 80px minimum height and add full text lines when descriptions wrap. The grid responds to available article width. Artwork and title tops align; the illustration is omitted below 640px. The theme control fits its contents.
+
+A simultaneous local check/build/smoke run exposed a race: the checker resets generated metadata while smoke reads it. Added the existing `docs-generated-files` mutex to the smoke task; the same combined invocation subsequently passed. No validation was disabled.
+
+The replacement artwork is saved as `src/docs/public/img/elephant-engraving.webp` (1402×1122, 433,646 bytes, alpha preserved). It was generated with the built-in image tool, then encoded as WebP using the already installed Sharp dependency without cropping or resizing. The original remains in the thread's generated-image directory. No new dependency or client-side illustration code was added.
+
+Generation prompt:
+
+> Use case: stylized-concept. Asset type: a refined monochrome editorial illustration for Oliphaunt, an embedded PostgreSQL developer library, to display at about 200 by 160 pixels beside a restrained documentation page title. Create a serious natural-history engraving of one adult Asian elephant in three-quarter profile, facing left. Crop composition to head, upper shoulder, and gracefully descending trunk; complete silhouette within frame. Strong sculptural anatomy and sweeping ear, elegant tusk, tiny natural eye. The elephant is drawn in ivory-white ink with finely controlled black-and-white stipple and old newspaper halftone dithering, like a beautifully art-directed 1980s computer print of a 19th-century scientific engraving. Deep negative spaces, crisp silhouette, intermediate tones ONLY from dot density. White ink highlights on genuinely transparent background, intended for a near-black #111111 website. Composition compact and square with 10% transparent breathing room, image centered. No type, letters, frame, border, logo, extra symbols, vegetation, setting, ground or drop shadow. Absolutely no cartoon, baby elephant, cute mascot, smiling face, geometric block shapes, flat clipart, plastic 3D render, rainbow color, gradient background or checkerboard backdrop. Rich detailed engraving but a readable silhouette at small display sizes. White/gray ink and transparency only; preserve actual transparent alpha.
+
+Verification: docs format, lint, check, production build and 49-file smoke passed. All 44 routes passed the 320px page audit; seven page/theme samples passed axe A/AA checks. Shared leading edges, page-title alignment, 80px row rhythm and absence of overflow were measured at 320, 640, 768, 1024, 1280, 1440 and 1920px. Keyboard navigation, copying, theme persistence, reduced motion and forced-color focus checks passed. The engraving sits within a 192×160px box without changing its aspect ratio, keeping the surrounding layout on whole spacing units. Full screen-reader and physical-device testing remain unverified.
+
+Review artifacts are under `docs-identity/` in the thread visualization directory. They include the mark studies, desktop/mobile/light/dark page captures, `grid-audit.json`, and `style-audit.json`. The earlier open-search ARIA limitation remains unchanged; it is not claimed as fixed by this visual revision.
diff --git a/src/docs/maintainers/docs-rewrite-audit.md b/src/docs/maintainers/docs-rewrite-audit.md
new file mode 100644
index 000000000..bd2715728
--- /dev/null
+++ b/src/docs/maintainers/docs-rewrite-audit.md
@@ -0,0 +1,193 @@
+# Documentation rewrite audit — 2026-09-08
+
+Historical results from September 8. For the rebased checkout, see [September 29 review](docs-rebase-audit.md).
+
+## Scope and target
+
+All **41 authored public pages** were read file by file and rewritten. All **44 generated routes** remain available: the authored pages plus the extension catalog, version matrix, and API index. The root README and seven public SDK READMEs were also rewritten. The docs-app README and design notes now describe the actual authoring workflow.
+
+The target is the current checkout, with its package versions treated as published as requested. Registry availability is not claimed as verified. Native/WASIX/runtime/extension products retain independent versions. Historical architecture, maintainer policies, and engineering reports are classified below and remain outside public content; they were not rewritten as consumer guides.
+
+Research was completed before the rewrite and distilled into the repository-local [authoring skill](../../../.codex/skills/write-oliphaunt-docs/SKILL.md), [source map](../../../.codex/skills/write-oliphaunt-docs/references/source-map.md), and [primary-source research](../../../.codex/skills/write-oliphaunt-docs/references/research.md). No external skill bundle or publishing service was installed.
+
+## Public page ledger
+
+Paths below are relative to `src/docs/content/`. Every listed page was rewritten. Source review identifies the implementation inspected; the validation ledger below distinguishes compilation from execution.
+
+| File | Original problem | Result | Source review |
+| --- | --- | --- | --- |
+| [`learn/embedded-postgres.mdx`](../content/learn/embedded-postgres.mdx) | Mixed storage internals and repeated extension introductions. | Storage choices, ownership, SQL, and recovery explained once. | Native/WASIX storage implementations; SDK close and transaction contracts. |
+| [`learn/index.mdx`](../content/learn/index.mdx) | Custom route map repeated the suggested paths. | Task-oriented guide index. | All six guide routes. |
+| [`learn/mobile-stability.mdx`](../content/learn/mobile-stability.mdx) | Broad assurances and close/reopen language hid application responsibilities. | Application ownership, persistent paths, background writes, restore across launches, and failure recovery. | Swift actor; Kotlin owner dispatcher; RN client and platform adapters. |
+| [`learn/native-runtime.mdx`](../content/learn/native-runtime.mdx) | Mode matrix mixed concepts, packaging, and generic SDK narration. | Direct/broker/server choice, session counts, ownership, and process-root lifetime. | Rust direct/server; JS runtime providers; native detach semantics. |
+| [`learn/sqlite-upgrade.mdx`](../content/learn/sqlite-upgrade.mdx) | A custom concept map took space without a concrete migration sequence. | Schema/type differences, parameter example, migration sequence, and selection tradeoffs. | PostgreSQL types and SQL; SDK storage/backup contracts. |
+| [`learn/tauri.mdx`](../content/learn/tauri.mdx) | Server helper returned only a connection URL, dropping its process owner. | Async managed database state, bound commands, retained server ownership, packaging, and shutdown. | Rust async/server implementation; Tauri state and command docs. |
+| [`reference/capabilities.mdx`](../content/reference/capabilities.mdx) | Custom summary mixed products and feature selection. | Runtime feature comparison plus platform requirements generated from policy. | SDK implementations; platform-compatibility-policy.mjs. |
+| [`reference/extensions.mdx`](../content/reference/extensions.mdx) | Artifact-flow diagrams, package validation, and repeated selection rules. | Select, package, enable SQL, handle dependencies, and upgrade. | Generated extension registry; SDK extension resolver/build integrations. |
+| [`reference/index.mdx`](../content/reference/index.mdx) | Custom lookup and steps described how to read reference. | Direct links to the lookups a developer needs. | Reference route manifest. |
+| [`reference/performance.mdx`](../content/reference/performance.mdx) | Decorative result grid and release measurements implied a reusable performance conclusion. | Measure startup/query/durability costs, compare equivalent workloads, and record conditions. | Actual SDK execution and storage behavior; no fabricated benchmark results. |
+| [`reference/releases.mdx`](../content/reference/releases.mdx) | First-release history and release machinery dominated consumer upgrade guidance. | Dependency compatibility, upgrade steps, version map, and honest build snapshots. | Release graph, centralized version substitutions, docs-version.json. |
+| [`reference/sdk-products.mdx`](../content/reference/sdk-products.mdx) | Release-product taxonomy duplicated SDK choice. | Package mapping and independent-version meaning; URL retained. | SDK and release manifests. |
+| [`sdk/c-abi/api-reference.md`](../content/sdk/c-abi/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | Native oliphaunt.h, ABI implementation and C smoke. |
+| [`sdk/c-abi/guide.mdx`](../content/sdk/c-abi/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Managed-root preparation, off-thread scheduling, response/error capture ownership, terminal close. | Native oliphaunt.h, ABI implementation and C smoke. |
+| [`sdk/c-abi/index.mdx`](../content/sdk/c-abi/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | Prepared-root prerequisite; complete C program; response ownership and SQL-versus-transport status. | Native oliphaunt.h, ABI implementation and C smoke. |
+| [`sdk/index.mdx`](../content/sdk/index.mdx) | Repeated chooser, mode matrix, and navigation instructions. | A single language/runtime chooser and shared concepts link. | SDK manifest; package entry points. |
+| [`sdk/kotlin/api-reference.md`](../content/sdk/kotlin/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | Kotlin Android facade, common query types, Gradle plugin, native owner. |
+| [`sdk/kotlin/guide.mdx`](../content/sdk/kotlin/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Typed params; transactions; matching Gradle/runtime selections; restore on next launch. | Kotlin Android facade, common query types, Gradle plugin, native owner. |
+| [`sdk/kotlin/index.mdx`](../content/sdk/kotlin/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | Matching plugin/dependency versions; coroutine example; Directory takes File. | Kotlin Android facade, common query types, Gradle plugin, native owner. |
+| [`sdk/react-native/api-reference.md`](../content/sdk/react-native/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | RN index/client, peer dependencies, config plugin, Swift/Kotlin adapters. |
+| [`sdk/react-native/architecture.mdx`](../content/sdk/react-native/architecture.mdx) | Transport internals and boundary diagram dominated app integration. | Native integration: Expo/bare iOS and Android packaging, lifecycle, and extension requirements. | RN config plugin; CocoaPods/Gradle integrations; Swift/Kotlin adapters. |
+| [`sdk/react-native/guide.mdx`](../content/sdk/react-native/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Transactions; install/select/rebuild extensions; restore on next launch; errors and shutdown. | RN index/client, peer dependencies, config plugin, Swift/Kotlin adapters. |
+| [`sdk/react-native/index.mdx`](../content/sdk/react-native/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | New Architecture and Expo native-build prerequisites; typed first query and app-data storage. | RN index/client, peer dependencies, config plugin, Swift/Kotlin adapters. |
+| [`sdk/rust/api-reference.md`](../content/sdk/rust/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | Rust builder, direct/async owners, rows/DecodeError, server, liboliphaunt adapter. |
+| [`sdk/rust/guide.mdx`](../content/sdk/rust/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Idiomatic queries/transactions; mode choice; extensions; restored root uses broker; cleanup. | Rust builder, direct/async owners, rows/DecodeError, server, liboliphaunt adapter. |
+| [`sdk/rust/index.mdx`](../content/sdk/rust/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | Complete compiled parameterized query; compatible error type and native storage lifetime. | Rust builder, direct/async owners, rows/DecodeError, server, liboliphaunt adapter. |
+| [`sdk/swift/api-reference.md`](../content/sdk/swift/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | Swift Oliphaunt actor/types; Package.swift and released package/extension generator. |
+| [`sdk/swift/guide.mdx`](../content/sdk/swift/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Queries/transactions; physical restore on next launch; actual generated extension product workflow. | Swift Oliphaunt actor/types; Package.swift and released package/extension generator. |
+| [`sdk/swift/index.mdx`](../content/sdk/swift/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | SwiftPM product installation, async function with imports/cleanup, and app-owned URL. | Swift Oliphaunt actor/types; Package.swift and released package/extension generator. |
+| [`sdk/typescript/api-reference.md`](../content/sdk/typescript/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | JS index/types/client; native bindings and direct/broker/server providers. |
+| [`sdk/typescript/guide.mdx`](../content/sdk/typescript/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Queries/transactions; exact extensions; broker restore; server ownership; Electron packaging. | JS index/types/client; native bindings and direct/broker/server providers. |
+| [`sdk/typescript/index.mdx`](../content/sdk/typescript/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | Versioned npm/Bun/Deno setup; strict-typed first query, cleanup, and persistent alternative. | JS index/types/client; native bindings and direct/broker/server providers. |
+| [`sdk/wasix-rust/api-reference.md`](../content/sdk/wasix-rust/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | WASIX Rust lib/oliphaunt modules, Cargo features, owner/runtime/tools. |
+| [`sdk/wasix-rust/dump-restore.mdx`](../content/sdk/wasix-rust/dump-restore.mdx) | Physical/logical formats, tool flags, and CLI usage were interleaved. | Choose physical backup or logical SQL; complete tools example and import constraints. | WASIX Rust tools API, PgDumpOptions, CLI entry points. |
+| [`sdk/wasix-rust/guide.mdx`](../content/sdk/wasix-rust/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Queries/transactions, explicit extensions, backup/restore, async owner, errors. | WASIX Rust lib/oliphaunt modules, Cargo features, owner/runtime/tools. |
+| [`sdk/wasix-rust/index.mdx`](../content/sdk/wasix-rust/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | Compiled first query, memory default, persistent directory, and thread-affine versus async ownership. | WASIX Rust lib/oliphaunt modules, Cargo features, owner/runtime/tools. |
+| [`sdk/wasix-rust/runtime.mdx`](../content/sdk/wasix-rust/runtime.mdx) | Repeated API descriptions and custom runtime diagram. | Thread affinity, owner placement, storage, concurrency, and server limits. | WASIX Rust owner/direct/server and storage implementations. |
+| [`sdk/wasix-typescript/api-reference.md`](../content/sdk/wasix-typescript/api-reference.md) | Lookup prose was sparse or mixed generated-artifact commentary with contract detail. | Visible API reference: entry points, options/defaults, operations, results, errors, and lifecycle limits. | WASIX TS exports/types/client, host storage, Worker/server and tools. |
+| [`sdk/wasix-typescript/guide.mdx`](../content/sdk/wasix-typescript/guide.mdx) | Long step/proof/summary wrapper repeated installation and mixed application recipes. | Transactions, host storage, tools, extensions, execution placement, server limits. | WASIX TS exports/types/client, host storage, Worker/server and tools. |
+| [`sdk/wasix-typescript/index.mdx`](../content/sdk/wasix-typescript/index.mdx) | Repeated SdkLanding/first-query sections and responsibilities delayed the runnable path. | Browser headers, host requirements, complete query, and persistent Worker alternative. | WASIX TS exports/types/client, host storage, Worker/server and tools. |
+| [`start/index.mdx`](../content/start/index.mdx) | Three custom flow panels obscured the entry point. | Product explanation, eight SDK links, and a short next-task list. | SDK manifest; all eight public entry points. |
+
+## Generated pages and shared UI
+
+| Source or output | Decision |
+| --- | --- |
+| `reference/extension-catalog` | Generated from extension metadata; title and introduction rewritten, setup linked, upstream version distinguished from package version. |
+| `reference/version-matrix` | Generated from the release graph; product, current version, and release link. Removed first-release history and internal build columns. Exposed in the sidebar. |
+| `reference/api-reference` | Generated index linking each SDK quickstart, guide, and API reference. |
+| `src/docs/moon.yml` | Added the source/type-config/platform-policy inputs read by docs checks so cached builds respond to those changes. |
+| `docs-manifest.toml` and generated metadata | One shallow sidebar; API references visible; active SDK expands; existing route URLs retained. |
+| Home and documentation layouts | Same Fumadocs reading shell; compact headings, useful breadcrumbs, copy Markdown, local contents. |
+| `global.css` | Replaced the large decorative stylesheet with a compact semantic theme, readable code, responsive cards, focus, and reduced-motion rules. |
+| `components/oliphaunt.tsx`, `docs-data.ts` | Eight plain language/runtime links with existing language icons; server rendered. |
+| `components/mdx.tsx` | Reused standard Fumadocs/Radix content primitives. Removed obsolete specialized proof/flow/summary components. |
+| Old hero/animation components | Deleted after checking callers; removed the unused direct Motion dependency. Fumadocs retains its own dependencies. |
+| Search | Changed the static route to export the Orama index and enabled Fumadocs static search. The previous static GET emitted an empty query response. Smoke now searches the exported index. |
+| Markdown exports | Removed the older generator that overwrote Next exports; SDK chooser resolves to actual Markdown links and versions match HTML. |
+| `check-docs-product.mjs` | Retained route, source, API, navigation, link, metadata, and generated-data checks. Replaced exact old-copy/layout assertions with invariants. |
+| `check-docs-snippets.mjs` | Type-checks complete TS quickstarts against current SDK sources in disposable projects. |
+| `smoke-built-site.mjs` | Checks real exported links/anchors and unresolved Markdown components/versions. |
+
+## README ledger
+
+| File | Result |
+| --- | --- |
+| [`README.md`](../../README.md) | Developer entry point with SDK links, basic operating model, and a contributing link; removed first-release and release-pipeline narration. |
+| [`src/sdks/rust/README.md`](../../src/sdks/rust/README.md) | Package introduction, installation, complete first query, storage/lifecycle limits, and canonical guide/API links. Removed duplicated low-level implementation notes and stale compatibility tables. |
+| [`src/sdks/js/README.md`](../../src/sdks/js/README.md) | Package introduction, installation, complete first query, storage/lifecycle limits, and canonical guide/API links. Removed duplicated low-level implementation notes and stale compatibility tables. |
+| [`src/sdks/swift/README.md`](../../src/sdks/swift/README.md) | Package introduction, installation, complete first query, storage/lifecycle limits, and canonical guide/API links. Removed duplicated low-level implementation notes and stale compatibility tables. Retained release-synchronized exact SwiftPM dependency; extension workflow is in the guide. |
+| [`src/sdks/kotlin/README.md`](../../src/sdks/kotlin/README.md) | Package introduction, installation, complete first query, storage/lifecycle limits, and canonical guide/API links. Removed duplicated low-level implementation notes and stale compatibility tables. Plugin setup links to the canonical versioned quickstart; release sync advances the README dependency pin. |
+| [`src/sdks/react-native/README.md`](../../src/sdks/react-native/README.md) | Package introduction, installation, complete first query, storage/lifecycle limits, and canonical guide/API links. Removed duplicated low-level implementation notes and stale compatibility tables. |
+| [`src/bindings/wasix-ts/README.md`](../../src/bindings/wasix-ts/README.md) | Package introduction, installation, complete first query, storage/lifecycle limits, and canonical guide/API links. Removed duplicated low-level implementation notes and stale compatibility tables. |
+| [`src/bindings/wasix-rust/crates/oliphaunt-wasix/README.md`](../../src/bindings/wasix-rust/crates/oliphaunt-wasix/README.md) | Package introduction, installation, complete first query, storage/lifecycle limits, and canonical guide/API links. Removed duplicated low-level implementation notes and stale compatibility tables. |
+| [`src/docs/README.md`](../../src/docs/README.md) | Replaced scaffold instructions with authoring, commands, centralized versions, snapshots, and honest verification limits. |
+| [`src/docs/DESIGN_GROUNDING.md`](../../src/docs/DESIGN_GROUNDING.md) | Replaced obsolete presentation-first mandate and progress checklist with reader-first design and visual-review criteria. |
+
+## Version maintenance
+
+Public MDX uses `@VERSION(product-id)@`; the generator resolves release metadata once and fails unknown IDs/invalid values. Install commands, release links, version table, and Markdown agree. The build emits `docs-version.json` with the full source revision, dirty flag, and product-version map. Archive it with the exported directory. A clean commit is required for a reproducible snapshot; a dirty flag alone does not preserve local changes.
+
+The release synchronizer now updates only standalone Swift/Kotlin README pins; public MDX is no longer subject to fragile version-string replacements. The existing synchronizer test exercises standalone pins and a second idempotent pass. Native platform prose is rendered directly from the existing compatibility policy. No platform support values changed.
+
+There is one current public documentation set. Historical hosted versions and a picker are not fabricated; source tags and archived build directories are the path to future snapshots.
+
+## Repository records retained outside the public site
+
+This is a scope/classification inventory, not a new correctness certification of old engineering records. These files remain useful to contributors; public pages no longer route developers into them for ordinary integration instructions.
+
+| File | Classification |
+| --- | --- |
+| `docs/README.md` | Repository documentation index; retained outside public navigation. |
+| `docs/architecture/cluster-seeds-and-icu.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/database-storage.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/final-product-source-architecture.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/ios.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/native-liboliphaunt.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/orm-integration-report.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/pglite-public-api-comparison.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/stable-database-api.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/architecture/wasix-typescript-napi.md` | Architecture/design reference; retained outside public navigation. |
+| `docs/internal/CI_RELEASE_PROCESS_AUDIT_2026-09-02.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/DONE.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/IMPLEMENTATION_CHECKLIST.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/MONOREPO_SIMPLIFICATION_PLAN_2026-09-04.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/OLIPHAUNT_PATCH_STACK.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/OLIPHAUNT_README.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/OLIPHAUNT_TRACK_REVIEW.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/PERFORMANCE.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/PG18_WASIX_PERF_STATUS.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/PG18_WASIX_POSTGRES.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/README.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/RELEASE_PIPELINE_READINESS_2026-09-03.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/REPOSITORY_ORGANIZATION_AUDIT_2026-09-03.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/TODO.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/WASIX_NODE_BULK_PERF_REVIEW_20260814.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/internal/WASIX_PATCH_STACK.md` | Internal or historical engineering record; retained outside public navigation. |
+| `docs/maintainers/README.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/assets.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/compiler-caching.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/consumer-dx-release-blueprint.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/development.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/extension-packaging-policy.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/mobile-stability-model.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/native-runtime-contract.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/performance-evidence.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/physical-archive-format.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/release-setup.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/release.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/repo-structure.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/rust-sdk-policy.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/sdk-api-surface.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/sdk-parity-policy.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/sdk-products-policy.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/testing.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/tooling.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/wasix-postmaster.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/wasix-usage.md` | Maintainer policy or procedure; retained outside public navigation. |
+| `docs/maintainers/windows-vc-runtime.md` | Maintainer policy or procedure; retained outside public navigation. |
+
+## Verification
+
+Completed on 2026-09-08 against the working tree. SDK execution is not implied by a passing docs build.
+
+| Check | Result |
+| --- | --- |
+| `pnpm --dir src/docs check` | Passed: generated content, 44 documentation routes, links, navigation, version substitution, MDX/site types, and three TypeScript quickstarts. |
+| `pnpm --dir src/docs build` | Passed: production static export, including the final platform wording and syntax theme. |
+| `pnpm --dir src/docs smoke` | Passed: 49 HTML files, internal links/anchors, assets, all 44 pages in Markdown exports, published version metadata, and a real Orama search query. |
+| `moon run release-tools:unit` | Passed using the repository-pinned Moon 2.5.4 binary; final full run completed in 4m 58s. Earlier attempts exposed a transient fixture timeout and a duplicate README sync rule; the rule was corrected before the successful run. |
+| Focused release/version/platform tests | 19 passed. |
+| Frozen dependency install | Passed; no new dependency added. Removed the unused direct motion dependency. |
+| Changed UI/tooling Biome checks, `git diff --check`, local skill validator | Passed. |
+| Native Rust first-query example | Compiled; execution requires the native library (`LIBOLIPHAUNT_PATH`), unavailable in this checkout. |
+| WASIX Rust first-query example | `cargo check` passed against checkout source; not executed. |
+| C first-query example | Strict C11 syntax check passed against the real header; not executed. |
+| Native TypeScript, React Native, WASIX TypeScript first-query examples | Strict type-checks passed against SDK source; database execution was not performed. |
+| Swift, Kotlin, Tauri and mobile packaging | Source-reviewed; no Apple/Android application execution or packaging qualification performed. |
+
+### Rendered-site review
+
+Reviewed the production export in Chromium at desktop and mobile sizes, in light and dark themes. All 44 documentation routes had one H1 and no page-level horizontal overflow at 320px. Wide tables and code blocks retain their own horizontal scrolling.
+
+Exercised search with a real backup query and navigation to its result, Ctrl+K/Escape, arrow-key installation tabs, mobile sidebar navigation to API reference, code copying, and Copy Markdown through clipboard paste. Copied installation commands contain resolved versions; copied Markdown contains SDK links without unresolved MDX components or version tokens.
+
+Visual inspection covered the SDK chooser, TypeScript quickstart, dark code blocks, and a narrow capability table. Switching the dark syntax theme to `github-dark-default` increased comment contrast against the code surface from 3.60:1 to 5.64:1.
+
+Review artifacts are retained locally outside the repository and published site: `before.png`, `desktop.png`, `typescript-dark.png`, `typescript-mobile.png`, `table-320.png`, and `layout-audit.json`.
+
+No registry publication, deployment, hosted CI qualification, or complete cross-platform SDK runtime execution is claimed. The version snapshot records this working tree as dirty; archive a clean-commit build for a reproducible released snapshot.
+
+
+## Published-release follow-up
+
+See [published-package verification](published-docs-verification.md) for fresh registry execution after publication, runtime setup corrections, and native release defects found. This supersedes the earlier source-only execution boundaries where new evidence is available.
diff --git a/src/docs/maintainers/published-docs-verification.md b/src/docs/maintainers/published-docs-verification.md
new file mode 100644
index 000000000..f562aabce
--- /dev/null
+++ b/src/docs/maintainers/published-docs-verification.md
@@ -0,0 +1,47 @@
+# Published-package documentation verification
+
+Historical results from September 8. For the rebased checkout, see [September 29 review](docs-rebase-audit.md).
+
+Checked on 2026-09-08 after the September releases, using fresh projects outside the workspace. No SDK source aliases or workspace dependencies were used in the executed consumer checks.
+
+## Release and API alignment
+
+| Surface | Published version | Evidence |
+| --- | --- | --- |
+| Native Rust | 0.2.0 | Installed from crates.io; API source matches `oliphaunt-rust-v0.2.0`. |
+| Native TypeScript | 0.2.0 | Installed from npm; API source matches `oliphaunt-js-v0.2.0`. |
+| Swift | 0.7.0 | SwiftPM tag `0.7.0` has the documented products, Swift 6/iOS 17/macOS 14 requirements, and a matching published XCFramework asset. API source matches the tag. |
+| Kotlin | 0.2.0 | Maven Central serves both the Android package POM and Gradle plugin marker POM; API source matches `oliphaunt-kotlin-v0.2.0`. |
+| React Native | 0.2.0 | npm metadata confirms React 19+, React Native 0.85+, and Expo 56+ peers. API source matches the release tag. |
+| WASIX TypeScript | 0.1.0 | Installed from npm; API source matches the release tag. |
+| WASIX Rust | 0.2.0 | Installed from crates.io; API source matches the release tag. |
+| Optional WASIX tools / pgTAP | 0.1.0 / 0.2.0 | Installed from npm and executed. |
+| Native runtime / vector | 0.2.0 / 0.2.0 | Native GitHub archive downloaded and used; vector npm version confirmed. |
+
+All seven SDK API source trees are unchanged between this docs checkout and their published source tags. This preserves the earlier page-by-page API audit, but does not establish that packaging or every runtime integration works.
+
+Primary package endpoints: [native npm SDK](https://registry.npmjs.org/@oliphaunt/ts/0.2.0), [WASIX npm SDK](https://registry.npmjs.org/@oliphaunt/wasix-ts/0.1.0), [React Native metadata](https://registry.npmjs.org/@oliphaunt/react-native/0.2.0), [Kotlin POM](https://repo.maven.apache.org/maven2/dev/oliphaunt/oliphaunt-android/0.2.0/oliphaunt-android-0.2.0.pom), [Kotlin plugin marker](https://repo.maven.apache.org/maven2/dev/oliphaunt/android/dev.oliphaunt.android.gradle.plugin/0.2.0/dev.oliphaunt.android.gradle.plugin-0.2.0.pom), [Swift manifest](https://github.com/f0rr0/oliphaunt/blob/0.7.0/Package.swift), [native release](https://github.com/f0rr0/oliphaunt/releases/tag/liboliphaunt-native-v0.2.0).
+
+## Executed consumer checks
+
+Host: Linux x64 GNU, Node.js 24.18.0, Bun 1.4.2. The workspace packages were not substituted for registry releases.
+
+- **WASIX TypeScript:** the exact first-query example printed `42`. Additional checks passed parameter binding, transaction commit/rollback, persistent close/reopen, physical backup/restore, pgTAP loading, a Worker handle, and logical `pgDump`/`psql` round-trip restoration.
+- **WASIX Rust:** the exact first-query example compiled from crates.io dependencies, ran, and printed `42`.
+- **Native Rust:** the original first-query example compiled but failed without `LIBOLIPHAUNT_PATH`. With the complete GitHub runtime archive under `OLIPHAUNT_RESOURCES_DIR/native-runtime/liboliphaunt-native` and `LIBOLIPHAUNT_PATH` pointing to its library, the same example printed `42`. These prerequisites are now documented.
+- **Native TypeScript:** a fresh npm install succeeded, but the exact first-query example failed in both Node and Bun with PostgreSQL's invalid data-directory permissions error. Changing the execution umask did not resolve it. This is now disclosed in the quickstart, SDK README, and upgrade reference.
+
+## Release defects found
+
+1. Native TypeScript copies the installed cluster seed with `fs.cp` and does not normalize the PGDATA root permissions. The installed seed root in this consumer was mode `0775`, while PostgreSQL accepts `0700` or `0750`. This prevents the default fresh database from reaching ReadyForQuery. No SDK patch or replacement package was published during this docs task.
+2. Native Rust's `register_build_resources!()` macro expands to the private `Error::InvalidConfig` associated function and fails with E0624 in an external consumer. Calling the public registration function directly compiles, but does not resolve the next defects.
+3. Native Rust library lookup still requires `LIBOLIPHAUNT_PATH`; registering a build resource directory does not configure it.
+4. The Cargo-staged native cluster seed omitted required empty directories: after explicitly setting the library path, initialization failed on missing `pg_notify`. The complete GitHub archive preserves these directories and works. The documented setup therefore uses that archive rather than the broken helper path.
+
+These are observations against the published 0.2.0 packages. Do not advance the limitation text to a later version automatically; remove or revise it only after repeating the fresh-consumer checks on a fixed release.
+
+## Boundaries
+
+Swift, Kotlin, React Native, browser IndexedDB/OPFS, C ABI execution, and non-Linux native targets were not executed in this environment. Registry presence, source equivalence, and platform metadata checks are not substitutes for app builds or device tests. No blanket claim that all released integrations work is justified.
+
+Consumer projects and logs are retained locally under `/tmp/oliphaunt-published-docs-audit/`. `pnpm --dir src/docs check`, `build`, and `smoke` passed after the corrections (49 exported HTML files). Their passing result does not override the native TypeScript failure.
diff --git a/src/docs/moon.yml b/src/docs/moon.yml
index b39d938e2..299b8d15a 100644
--- a/src/docs/moon.yml
+++ b/src/docs/moon.yml
@@ -11,7 +11,7 @@ dependsOn:
project:
title: "Oliphaunt Docs"
- description: "Latest public guides and completed product releases."
+ description: "Developer guides, SDK references, and release versions."
owner: "oliphaunt"
tasks:
@@ -26,6 +26,8 @@ tasks:
- "**/*"
- "/src/extensions/generated/extensions.catalog.json"
- "/release-please-config.json"
+ - "/.release-please-manifest.json"
+ - "/tools/release/platform-compatibility-policy.mts"
- "/bun.lock"
options:
cache: false
@@ -46,6 +48,8 @@ tasks:
- "**/*"
- "/src/extensions/generated/extensions.catalog.json"
- "/release-please-config.json"
+ - "/.release-please-manifest.json"
+ - "/tools/release/platform-compatibility-policy.mts"
- "/bun.lock"
outputs:
- "/target/docs/build/**/*"
@@ -65,3 +69,4 @@ tasks:
- "tools/smoke-built-site.mts"
options:
cache: false
+ mutex: "docs-generated-files"
diff --git a/src/docs/package.json b/src/docs/package.json
index 49b0885c5..dede350e8 100644
--- a/src/docs/package.json
+++ b/src/docs/package.json
@@ -5,8 +5,8 @@
"scripts": {
"dev": "bun run generate && next dev --hostname 127.0.0.1",
"generate": "bun tools/generate-content.mts && fumadocs-mdx",
- "check": "bun tools/check-docs-product.mts && next typegen && fumadocs-mdx && tsc --noEmit",
- "build": "bun run generate && next build && bun tools/publish-next-export.mts",
+ "check": "bun tools/check-docs-product.mts && next typegen && fumadocs-mdx && tsc --noEmit && bun tools/check-docs-snippets.mts",
+ "build": "bun run generate && bun tools/check-docs-snippets.mts && next build && bun tools/publish-next-export.mts",
"smoke": "bun tools/smoke-built-site.mts",
"lint": "biome check",
"format": "biome format --write",
@@ -19,7 +19,6 @@
"fumadocs-mdx": "15.0.10",
"fumadocs-ui": "16.9.3",
"lucide-react": "^1.17.0",
- "motion": "13.1.0",
"next": "16.2.7",
"react": "19.2.7",
"react-dom": "19.2.7",
diff --git a/src/docs/proxy.ts b/src/docs/proxy.ts
index 224268160..a47e1e214 100644
--- a/src/docs/proxy.ts
+++ b/src/docs/proxy.ts
@@ -1,5 +1,5 @@
-import { NextRequest, NextResponse } from 'next/server';
import { isMarkdownPreferred, rewritePath } from 'fumadocs-core/negotiation';
+import { type NextRequest, NextResponse } from 'next/server';
import { docsContentRoute, docsRoute } from '@/lib/shared';
const { rewrite: rewriteDocs } = rewritePath(
diff --git a/src/docs/public/img/elephant-engraving.webp b/src/docs/public/img/elephant-engraving.webp
new file mode 100644
index 000000000..267be2499
Binary files /dev/null and b/src/docs/public/img/elephant-engraving.webp differ
diff --git a/src/docs/public/img/favicon.svg b/src/docs/public/img/favicon.svg
index 91de85e67..da02fbd00 100644
--- a/src/docs/public/img/favicon.svg
+++ b/src/docs/public/img/favicon.svg
@@ -1,6 +1,4 @@
-