Skip to main content

Independent verification layer for software projects

Project description

Assay

PyPI License: AGPL-3.0-only

Visual verification for software projects.

Assay captures browser screenshots, computes pixel-level diffs against approved baselines, and surfaces results through a dashboard with a before/after slider. It runs Playwright tests in Docker and delivers structured results to a Grain workflow via an ingest API.


Features

  • Visual diff — pixel-level comparison of screenshots against approved baselines; highlights regressions in red
  • Before/after slider — side-by-side and overlay views in the dashboard
  • Baseline management — approve or reject baseline updates per check; no silent regressions
  • Screenshot gallery — browseable dashboard with thumbnails, check status, and diff overlays
  • Scheduled runs — cron-based scheduling with configurable suites and targets
  • Grain integration — ingest results directly into a Grain task packet for structured review and closure
  • Browser SDK — TypeScript SDK for capturing screenshots and metadata from inside your app
  • Docker runner — isolated Playwright execution with a prebuilt image

Requirements

  • Python 3.11+
  • Docker (for assay run)
  • Node.js 18+ (for the TypeScript browser SDK)

Install

uv tool install assay-kit

Or with pip:

pip install assay-kit

Or from source:

git clone https://github.com/Diwata-Labs/Assay.git
cd Assay
pip install -e .

Quick start

1. Configure

Create assay.toml in your project root (all fields optional — defaults shown):

[project]
name = "my-project"

[runner]
docker_image = "assay-playwright:latest"
timeout_seconds = 300

[output]
directory = "./assay-output"

[serve]
host = "127.0.0.1"
port = 8000

[keys]
store = "~/.assay/keys.json"

[schedule]
store = "~/.assay/schedules.json"

2. Run a test

assay run --target https://your-app.example.com

Exit codes: 0 = pass, 3 = fail, 1 = inconclusive or error.

3. Start the ingest server

# Create an API key first
assay key create --name ci

# Start the server
assay serve

4. Open the dashboard

Navigate to http://localhost:8000 to see the screenshot gallery, check results, and diff views.

5. Schedule recurring runs

# Add a schedule (standard 5-field cron)
assay schedule add --cron "0 8 * * *" --suite smoke --target https://your-app.example.com

# List schedules
assay schedule list

# Start the scheduler (foreground; Ctrl+C to stop)
assay schedule run

# Remove a schedule
assay schedule remove <id>

Dashboard

The Assay dashboard (assay serve) provides:

  • Screenshot gallery — thumbnails for every captured check, sorted by run
  • Check results — pass/fail/inconclusive status per check with diff metadata
  • Visual diff viewer — side-by-side before/after comparison with a draggable overlay slider
  • Baseline management — approve a new baseline or reject and keep the existing one per check

Baselines are stored locally alongside your output directory. Approving a baseline makes it the reference for future runs.


Grain integration

Assay results can be ingested directly into a Grain task packet for structured review before closure.

The ingest API is protected by API key auth. Create a key before starting the server:

assay key create --name grain
assay key list

The ingest endpoint accepts structured payloads from the browser SDK or from assay run. Grain reads the result via:

grain verify submit --id TASK-0001
grain verify status --verification-id VERIFY-0001-001

Browser SDK

The browser SDK is for human/in-app capture from a real browser. It is not the agent path — its capture() reads the live DOM and throws outside a browser. Agents should use the CLI, POST /ingest, or MCP (see Agent / programmatic access).

Install the TypeScript SDK in your web app:

npm install @diwata-labs/assay-sdk
import { AssaySDK } from "@diwata-labs/assay-sdk";

const sdk = new AssaySDK({
  apiKey: "your-api-key",
  endpoint: "http://localhost:8000",
});

// Capture a screenshot and metadata, POST to /ingest
await sdk.capture({ comment: "Optional human note" });

The SDK captures the current viewport, serializes metadata, and POSTs to the ingest endpoint. Results appear in the dashboard immediately.


Agent / programmatic access

Assay is fully familiar-drivable: an agent can run the entire verification loop headlessly, with no browser and no dashboard. Agents use the CLI, POST /ingest, or the MCP server — never the browser SDK (its capture() is DOM-locked and throws in Node).

The machine-readable contract — every tool, its JSON Schema, and the HTTP endpoints — lives at src/assay/contracts/tool_manifest.json and is served at GET /mcp/manifest. Treat that as the source of truth.

Three agent surfaces

  1. CLI — the most complete surface. Every agent-relevant command takes --format json:

    assay init --non-interactive --admin-email a@b.com --admin-password "$PW" --format json
    assay run --target https://app.example.com --task-id TASK-0001 --format json
    assay check --format json
    assay key create --name agent --format json
    assay baseline approve VERIFY-0001-001 --format json
    assay baseline list --format json
    

    assay init --non-interactive (alias --yes) never prompts or reads a TTY — pass the admin email/password as flags or via ASSAY_ADMIN_EMAIL / ASSAY_ADMIN_PASSWORD for zero-touch setup.

  2. POST /ingest — submit a captured screenshot payload directly. Authenticated with the X-Assay-Key header. The request body conforms to the JSON Schema src/assay/schemas/sdk_ingest.schema.json; the stored result conforms to src/assay/schemas/assay_payload.schema.json.

  3. MCP serverGET /mcp/tools, GET /mcp/manifest, POST /mcp/call. All /mcp/* and /baselines* routes require a valid API key (X-Assay-Key). The tools cover the full loop:

    tool purpose
    run_verification trigger a real run; returns verification_id + outcome + diff
    get_report structured report for a verification_id
    get_status poll a verification_id (pending / complete)
    list_runs list runs, filter by task_id / outcome
    list_baselines list set baselines
    approve_baseline / reject_baseline / set_baseline drive the baseline workflow
    KEY=$(assay key create --name agent --format json | tail -1 | python -c 'import sys,json;print(json.load(sys.stdin)["key"])')
    
    curl -s localhost:8000/mcp/call -H "X-Assay-Key: $KEY" \
      -d '{"tool":"run_verification","input":{"target":"https://app.example.com"}}'
    
    curl -s localhost:8000/mcp/call -H "X-Assay-Key: $KEY" \
      -d '{"tool":"approve_baseline","input":{"verification_id":"VERIFY-0001-001"}}'
    

Baselines are also manageable headlessly over API-key HTTP: GET /baselines, POST /baselines/set|approve|reject (body {"verification_id": "..."}) — no dashboard needed.


Docker runner

The assay run command requires a pre-built Docker image containing Playwright.

Build locally

cd runner
docker build -t assay-playwright:latest .

Use a custom image

[runner]
docker_image = "myregistry.example.com/assay-playwright:latest"

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Lint
ruff check src/ tests/

# Type check
mypy src/assay

License

AGPL-3.0-only. Commercial licensing for closed-source or hosted use: ss@diwata.domains

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

assay_kit-0.3.2.tar.gz (150.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

assay_kit-0.3.2-py3-none-any.whl (104.8 kB view details)

Uploaded Python 3

File details

Details for the file assay_kit-0.3.2.tar.gz.

File metadata

  • Download URL: assay_kit-0.3.2.tar.gz
  • Upload date:
  • Size: 150.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for assay_kit-0.3.2.tar.gz
Algorithm Hash digest
SHA256 fa254b2bf36d7676b47883ce79685f6b163be277372d929ced84b00e8620f3a3
MD5 78963d8fa3c5c4330e6321503dc455ed
BLAKE2b-256 425a19f1cf20613d36c2f2f0a0c9b03e528a2ba6d1736914dd201a7a3ae929a7

See more details on using hashes here.

File details

Details for the file assay_kit-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: assay_kit-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 104.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for assay_kit-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 77bb0270b95c1aed88d60b161602bea313f461e1f0a7cad79635d0e6a95f3b0c
MD5 c6df5834853aca96f9e8457e48995b6d
BLAKE2b-256 375089b99a53404779473769a67bd05481caff671ca1459cf36e9d85959b9bf9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page