Self-host in 15 minutes
You will stand up your own YawningFace Block cloud: a Supabase database for storage, an Auth0 tenant for sign-in, and this repo deployed to Vercel. Everything fits in the free tiers. You need a GitHub account and a terminal with curl.
Heads-up: there is no dashboard UI in v1. The desktop app and the HTTP API are the interface - step 5 shows how to edit your config with curl.
1Create the Supabase project
Go to supabase.com and create a new project (any region, free tier is fine). Once it is ready:
- Open SQL Editor, paste the contents of
supabase/migrations/0001_init.sqlfrom this repo, and run it. It creates theprofiles,devices,configsandeventstables and enables RLS with no policies (only the server, using the service-role key, can touch the data). - In Project Settings → API, copy the Project URL (this is
SUPABASE_URL) and the service_role key (this isSUPABASE_SERVICE_ROLE_KEY). Treat the service-role key like a root password - it never leaves the server.
2Create the Auth0 tenant
Sign up at auth0.com (free tier) and create a tenant. You need two things: an API (so tokens carry the right audience) and a Native application (so the desktop app can sign in with a device code).
a) Create the API. In Applications → APIs → Create API:
- Name: anything, e.g. YawningFace Block.
- Identifier: a URI you control, e.g.
https://block.example.com/api. This exact string is yourAUTH0_AUDIENCE. - In the API's Settings, enable Allow Offline Access (clients need refresh tokens so you do not have to sign in every day).
b) Create the Native application. In Applications → Applications → Create Application, pick Native. Then in its Settings → Advanced Settings → Grant Types, make sure Device Code and Refresh Token are enabled, and save.
c) Note your values. From the tenant/application settings, write down the Domain (e.g. your-tenant.eu.auth0.com - this is AUTH0_DOMAIN, no https://) and the Native application's Client ID (the desktop app asks for it at sign-in).
3Deploy this repo to Vercel
Fork or push this repository to your GitHub account, then import it at vercel.com/new. Vercel detects Next.js automatically. Before deploying, set the environment variables (Project → Settings → Environment Variables):
AUTH0_DOMAIN=your-tenant.eu.auth0.com
AUTH0_AUDIENCE=https://block.example.com/api
SUPABASE_URL=https://YOUR-PROJECT.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ... # service_role key from step 1
NEXT_PUBLIC_SITE_URL=https://your-deployment.vercel.appDeploy, then verify the API is alive:
curl https://your-deployment.vercel.app/api/health
# → {"ok":true}4Install the desktop app and sign in
Download the app for Mac or Windows from the latest release. On first launch, point it at your cloud: enter your deployment URL, your Auth0 domain, the Native app's Client ID, and the API audience from step 2.
The app then shows a short device codeand opens your browser to Auth0's activation page. Confirm the code, sign in (or sign up), and the app receives its tokens - this is the Device Authorization Flow, the same thing your TV apps use. From then on it syncs your config from GET /api/v1/config and reports events back automatically.
5Edit your config via the API
Your blocklists live in one JSON document (the full schema is in docs/schema.md). To edit it, you need an access token. The easiest way to get one is to copy it from the desktop app's settings; any token obtained from your Auth0 tenant with the right audience works.
Read your current config:
export TOKEN="eyJ..." # your access token
export BASE="https://your-deployment.vercel.app"
curl -s "$BASE/api/v1/config" -H "Authorization: Bearer $TOKEN"Update it - for example, block Twitter and LinkedIn on weekday mornings everywhere:
curl -s -X PUT "$BASE/api/v1/config" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"config": {
"version": 1,
"blocklists": [
{
"id": "morning-focus",
"name": "Morning Focus",
"metadata": {
"enabled": true,
"severity": "block",
"devices": ["desktop", "mobile", "tablet"],
"timeZone": "Europe/Madrid",
"timePeriods": [
{ "startTime": "09:00", "endTime": "13:00", "schedule": ["mon","tue","wed","thu","fri"] }
]
},
"targets": { "websites": ["twitter.com", "linkedin.com"], "apps": ["Discord", "Steam"] },
"exceptions": []
}
]
}
}'Every signed-in device picks the new config up on its next sync. That's it - your attention now has a bouncer on every door.