Sayncv0.1.1
For React developers/Open source · MIT/v0.1.1

Inline contracts for your UI. Verified on every save.

Wrap a <button> — declare the API it should call. Wrap a <form> — declare what it submits and where it redirects. Wrap an <input> — declare its validation rules.

A Playwright-driven agent boots your app on every save, drives every contract, and reports every drift between expected and observed — in a dashboard at localhost:3777, inside your repo. No SaaS, no signup, no test files.

$npm install --save-dev saync-web
react · 18 lines
import { SayncButton } from 'saync-web/react';

export function AddToCartButton({ productId }) {
  return (
    <SayncButton
      name="add-to-cart"
      expects={{
        onClick: {
          apiCall: {
            method: 'POST',
            url: '/api/cart',
            expectedStatus: 200,
            maxDuration: 500,
          },
          responseShape: { cartCount: 'number' },
        },
      }}
      onClick={() => addToCart(productId)}
    >
      Add to cart
    </SayncButton>
  );
}
✓ contract registered · 1 expectationlocalhost:3777
01

What the agent verifies

Every contract you declare on a component is a real assertion. The agent drives the app via Playwright, observes the resulting DOM and network activity, and reports precise expected vs observed diffs.

Contract
Applies to
Asserts
  • apiCallButton, Form, Input, Select, Checkbox, …method, URL, expectedStatus, maxDuration
  • responseShapeany contract with apiCallJSON field types match the declared shape
  • validationInput, Textarea, Select, Slider, FileInputrequired, pattern, minLength, maxLength, message
  • onSubmitFormsubmit fires the API, response matches, optional reset
  • navigationLink, NavLinkclick lands at the declared URL
  • disclosureModal, Dialog, Drawer, Popover, Menuopen/close on Escape, outside-click, backdrop
  • flowmulti-step user journeysevery step reaches the declared end state
02

Anatomy of a verification

One contract. Three artifacts. Source, agent action, dashboard issue — all linked.

Source
<SayncButton
  name="checkout"
  expects={{
    onClick: {
      apiCall: {
        method: 'POST',
        url: '/api/orders',
        expectedStatus: 200,
        maxDuration: 400,
      },
    },
  }}
>
  Place order
</SayncButton>
Agent
  1. [01] register data-saync-name="checkout"
  2. [02] navigate http://localhost:3000
  3. [03] playwright.click('checkout')
  4. [04] capture network: POST /api/orders
  5. [05] observed status 500
  6. [06] observed duration 1.2s
  7. [07] screenshot.png · 18 KB
  8. [08] post to /api/runs/:id/results
Issue
high
Place order · onClick
3× seen · first 4m ago
Expected
200 · <400ms
Observed
500 · 1.2s
03

The honest Q&A

Hard questions, terse answers. No marketing.

How is this different from a Playwright test suite?+
Playwright tests live in a separate directory and describe scenarios. Saync contracts live next to the component and describe behavior. The agent generates the scenario — you only declare what should happen, not how to test it. A typical React app of ~200 components needs zero test files; the contracts in the components are enough.
Where does my data go?+
Into .saync/saync.db inside your repo. Saync runs as a Next.js server on localhost — nothing leaves your machine. The only outbound HTTP is the optional "Generate AI report" call, and even that uses your own LLM key (WatsonX / OpenAI / Anthropic).
Can I run this in CI?+
Yes. saync run is a one-shot command: boot your app, run the agent, exit with the right status code. Drop it into any GitHub Actions / GitLab / CircleCI workflow. The SQLite DB also serves as a structured artifact you can upload.
What about production traffic?+
Set mode="report" on <Saync.Provider> and the SDK observes real user interactions, batches violations, and POSTs them to a Saync instance running alongside your app. Production violations appear next to your local runs in the same dashboard.
04

60-second install

Four lines. No config file required. Add a Provider, wrap a component, you're done.

  1. [01]Install
    bash
    npm install --save-dev saync-web
  2. [02]Script
    json
    { "scripts": { "saync": "saync start" } }
  3. [03]Wrap
    tsx
    import { Saync } from 'saync-web/react';
    <Saync.Provider mode="log">{children}</Saync.Provider>
  4. [04]Boot
    bash
    npm run saync

    Open localhost:3777. Your data lives at .saync/saync.db in your repo.