A complete product, built on the SDK. A small task tracker to learn from and test against.

Runs locally on ports 5173 and 8787; code private during the alpha.

localhost:5173
Satin Reference App
My tasksFind

Today 4

Next 5

Blocked 1

The seeded people and tasks. Titles are always text: WEB-10 shows its markup, harmlessly.

Everything a real integration needs, in one app. The SDK's test bed and vendor demo. Its look is deliberately not Satin's.

Its own API. A Node server (port 8787) that checks every permission, refuses stale changes (409) and ignores repeats.

A classic view. The product's normal screen: projects, a task table and a detail panel. Always one action away.

My OwnUX. OwnUX surfaces in the app's own components: Today, Next, Blocked, task detail and Find.

Three people. Asha and Chen may edit; Ben may only view. The API, not OwnUX, decides.

A rollout with a holdout. 30% held out (salt reference-5). Asha and Ben get OwnUX; Chen stays on the classic view.

Signed settings. In development, the API makes an in-memory signing key and serves good and bad signed files.

Run it with one command. Run from the monorepo root. The repo is private, so only Satin's team can.

  1. 1

    Start it

    pnpm ref starts the API on port 8787 and the web client at http://localhost:5173.

  2. 2

    Switch people

    Use Signed in as to move between Asha (editor), Ben (viewer) and Chen (editor, in the holdout).

  3. 3

    Open the test panel

    In development only: script a failure, let Chen edit first, add a duplicate title, serve a signed file.

  4. 4

    Run the checks

    Unit tests, Playwright in Chrome with an accessibility scan, and ownux test. The app passes L2.

Terminal, from satin/
$ pnpm ref
# The API on port 8787, the web client at http://localhost:5173
$ pnpm test --project reference-app
# The API, and the end-to-end read path through the SDK
$ pnpm test:e2e
# Playwright in the installed Google Chrome, including an accessibility scan
$ pnpm ownux test --config apps/reference-app/ownux.config.ts
# Conformance: L1 Declared, then L2 Verified
web/src/App.tsx, the rollout
const ROLLOUT: RolloutPolicy = {
percentage: 100,
holdout: 0.3,
salt: "reference-5",
templates: "1",
};

In developmentThe Reference App runs locally.

The test panel

Break it on purpose. Script how the next change fails, then watch OwnUX tell the truth.

The development-only test panel can make the next change wait, fail, time out or vanish. OwnUX says Done only when the product shows the new value.

  • At most one retry, within a 2-second budget.
  • Time-outs are read back, not retried: it may have landed.
  • Other outcomes say what happened and what to do next.
How verified actions work

Test panel (development only)

Next change will…

WEB-4 · Asha Rao

Fix login redirect

Due 30 Oct

The whole integration, on one screen. The Reference App's real integration, and the target ownux test runs against.

web/src/integration.ts (excerpt)
export function referenceBinding(user: string, options: { base?: string; origin?: string } = {}) {
const origin = options.origin ?? globalThis.location.origin;
const base = options.base ?? "";
return createIntegration(manifest, {
workspace_id: WORKSPACE,
list: () => api<Page<Task>>("/tasks?view=mine", user, base),
search: ({ text }) =>
api<Page<Task>>(`/tasks?view=search&q=${encodeURIComponent(text)}`, user, base),
get: (ref: TaskRef) => api<Task>(`/tasks/${encodeURIComponent(ref.id)}`, user, base),
deepLink: (ref) => `${origin}/browse/${encodeURIComponent(ref.key ?? ref.id)}`,
homeLink: () => `${origin}/`,
execute: async (capability, input, ctx) => {
const { task_ref, ...rest } = input;
await api(`/tasks/${encodeURIComponent(task_ref.id)}`, user, base, {
method: "PUT",
body: JSON.stringify({ capability, input: rest, ...ctx }),
});
},
options: (capability, ref, query) =>
api<Option[]>(
`/tasks/${encodeURIComponent(ref.id)}/options?capability=${capability}${query ? `&q=${encodeURIComponent(query)}` : ""}`,
user,
base,
),
});
}
ownux.config.ts (excerpt)
export default defineConformanceTarget({
manifest: manifest.data,
task: { workspace_id: WORKSPACE, id: "t-101" },
connect: (as) => referenceBinding(as === "editor" ? "p-asha" : "p-ben", { base, origin: ORIGIN }),
reset: async () => {
await fetch(`${base}/api/dev/reset`, { method: "POST" });
},
close: () =>
new Promise((resolve) => {
server.close(() => {
resolve();
});
}),
});

The target starts the API on a free port with seeded data. Asha is the editor, Ben the viewer. Checks change t-101.

Reference App questions, answered.

An SDK is only as honest as the product it runs in. A real API, with permission checks, version stamps and failure modes, rules out shortcuts a real product would never offer.

Put your product where the Reference App is. The design partner programme is a free 12-week pilot.