Adaptive surfaces, built from your own components. Every person uses your product their way.
In development · SDK alpha in our Reference App · Not yet published
import { defineManifest } from "@satin/ownux/integration"; export const manifest = defineManifest({ app: { id: "acme-projects", version: "1.4.0" }, actions: { "task.list_assigned": READ, "task.search": READ, "task.get": READ, "task.set_due_date": { ...WRITE, input: { task_ref: "task.ref", due_date: "date" }, }, }, locked: ["billing", "security", "consent"],});Step 1 of 3 · Declare what OwnUX may offer
L1 Declared
Every action has a risk, preconditions, a verify step and a fallback.
Surfaces stay off unless L1 passes.
A small API, React first. Declare actions, connect your API, render surfaces. These are the alpha’s exports.
import { OwnUXProvider, OwnUXSettings, OwnUXSurface } from "@satin/ownux"; <OwnUXProvider manifest={manifest} binding={binding} components={myComponents} tokens={tokens} appName="Acme Projects" user={{ id: currentUser.id }} rollout={{ percentage: 25, holdout: 0.1, salt: "pilot-1", templates: "1" }} onNativeView={() => showClassicView()} onFallback={(reason, notifyKey) => showClassicView(reason, notifyKey)} onAudit={(event) => auditLog.write(event)}> <OwnUXSurface template="task_list" /> <OwnUXSettings /></OwnUXProvider>;// Map OwnUX's spacing and text size to your design tokensconst tokens = { space: { sm: "6px", md: "10px", lg: "16px" }, font_size: "15px",};- defineManifest({ app, actions, locked })
- Declares each action’s input, risk, preconditions, verify step and fallback, plus locked screens. Surfaces stay off until L1 passes.
- createIntegration(manifest, handlers)
- Maps your list, search, get, execute and options calls to OwnUX. Only declared capabilities are offered.
- <OwnUXProvider>
- Runs the Action Broker in your page, loads and saves Interface DNA, health-checks your integration and adds the coexistence marker.
- <OwnUXSurface template>
- One surface: task_list, task_finder, task_detail or quick_actions. Locked screens never render.
- useOwnUX()
- ready, active, cohort, dna, preferences, update, reset, exportProfile and importProfile, for your own UI.
- <OwnUXSettings />
- In-product settings in plain words: spacing, layout, words, start with, input, contrast, text size and less motion.
Code outside the page, such as ownux.config.ts, imports defineManifest and createIntegration from @satin/ownux/integration (no React).
Your components
Compose surfaces from your own design system. OwnUX decides what goes where. Your components decide how it looks.
Every surface is built from 17 primitives, such as Row, Section and DatePicker. Register one of your components for each and map your tokens. Start from plainRegistry.
- Deterministic: the same input always gives the same surface.
- Surfaces are validated: no control without a capability behind it.
- Content renders as text, never HTML: markup creates no element.
components={plainRegistry}
17 primitives · hover one to find it
task_list
Today
Blocked
Nothing is blocked.
task_detail
Fix login redirect
Verified writes
Nothing is done until your product says so. Every change goes through the Action Broker.
Changes are prepared, confirmed if your policy asks, then committed. The broker calls your execute handler once, then reads the task back to check the new value.
- More than one match asks “which task?” and changes nothing.
- A task edited by someone else is never overwritten.
- A repeated commit returns the first result: no double writes.
- One content-free audit event per change goes to your log.
The person sets HQ-7 · Fix login redirect due on 25 Oct. Pick what happens next.
prepare
Finds HQ-7 and checks the change is allowed. Writes nothing.
commit
Re-reads HQ-7. Version 14, unchanged since the person saw it.
execute
Calls your API once, with an idempotency key.
read back
Your product shows due date 25 Oct.
Signed configuration
Kill switch: can’t be forged, replayed or forgotten. Switch changes off remotely, from a file only you can sign.
Pin your public keys and supply a function that fetches the signed file. If it switches you off, changes stop and surfaces hand back to your view. Reading keeps working.
- Tampered, expired, older or unknown-key files are ignored.
- Last valid file kept in browser storage, applied before render.
- An accepted kill switch stays on past expiry until replaced.
Signed configuration
in force: serial 1792713600Serve a file
{ "key_id": "acme-2026-a",
"payload": "eyJmb3JtYXQiOiJvd251eC1jo…",
"signature": "kq9X2vR7…" }
// payload: serial 1792713600, kill: []Pick a file. Only a valid, newer file signed with a pinned key can change anything.
What the person sees Changes on
Built so AI coding tools can integrate it. The SDK ships all an assistant needs to integrate and test; you review.
A guide written for AI tools. AGENTS.md ships in the package, indexed by llms.txt: rules, the Task contract, errors and checks.
Starter files with the steps marked. ownux init writes a manifest that passes L1, and an integration with only TODO(ownux) steps left.
A fix on every failed check. Every failure prints Fix: with exactly what to change, so the loop converges.
A clear finish line. Done means Publishable: yes. Fresh AI agents have integrated unfamiliar products from the package alone.
$ npx ownux init src/ownux --app acme-projects✓ Wrote 5 starter files to src/ownux: AGENTS.md, manifest.ts, integration.ts, ownux.config.ts, view.tsx $ npx ownux test --config src/ownux/ownux.config.tsOwnUX conformance v0: acme-projects 1.4.0✓ L1 Declared✗ L2 Verified (test task HQ-7, as an editor and a viewer, reset 10 times) ✗ task.get: for a missing task, get threw Request failed, not ProviderError("not_found") Fix: For a task that does not exist, or that this person cannot see, get must throw new ProviderError("not_found", message). Map your API's not-found error to it.Not publishable: 1 check failed (marked ✗ above).Ask your assistant to follow src/ownux/AGENTS.md until the check passes. Review the result, especially that your API decides who may edit.
Small by design, honest about its status. The build enforces a size budget. A short list shows what the alpha lacks.
- SDK size, gzipped, without React
- 52.8 KBSDK size, gzipped, without ReactMeasured at the alpha
- Size budget for the SDK
- 60 KBSize budget for the SDKA budget: the size check fails the build above it
- primitives you map to your components
- 17primitives you map to your componentsFrom Surface and Row to Notice
- task capabilities in the alpha
- 6task capabilities in the alphaList, search, read; due date, status, assignee
In developmentThe OwnUX SDK is in development. An alpha runs in the Reference App with rollout and holdout, template pinning and local metering.
- React only. Other frameworks come later.
- Tasks only: the six capabilities above.
- Nothing is sent to a server yet.
- The package isn’t published yet.
Not yet. Every package is private while the SDK is in development. The alpha runs in our Reference App, a small task tracker built on the SDK. Design partners get access first.