Codync
A free, open-source 1:1 alternative to Grok Bot and Muse. Message Claude Code, Codex, Cursor and 40+ coding agents as persistent bots from your iPhone, Mac or Linux desktop. Group chats, threads, appr
Self-hosted endpoint monitoring. Write conditions as expressions and find out when things leave expected parameters.
Translation pending
Developer toolsPHP · BladeGitHub @returnearlyOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Database-backed endpoint monitoring. Gatus-shaped conditions, Filament admin, GraphQL mutations, Prometheus metrics, Reverb live events.
serversideup/php:8.5-frankenphp with Laravel Octane, OPcache, and FrankenPHP worker modeHTTP_PROXY / ALL_PROXY for HTTP checks and notification webhooks[STATUS], [BODY], [REDIRECT], [RESPONSE_TIME], [IP], [CONNECTED], [CERTIFICATE_EXPIRATION], [DOMAIN_EXPIRATION], [DNS_RCODE]returnearly/terraform-provider-nominalcomposer install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
php artisan serve
Admin: http://localhost:8000/admin
Notification channels, probes, users, and API tokens live under Settings.
Create a GraphQL/Terraform token from Settings → API Tokens, or:
php artisan nominal:token [email protected]
Run checks locally:
php artisan nominal:dispatch-due-checks
php artisan queue:work --queue=checks.local,default
INTERFACE_AUTH controls the Filament admin only. GraphQL always uses Sanctum tokens.
| Value | Behavior |
|---|---|
login | Email and password (default). Seeded: [email protected] / password |
none | No login page. Visitors are signed in as [email protected] (created on first visit). |
cloudflare | Cloudflare Access via returnearly/laravel-cloudflare-zero-trust. SSO users are created on first request. |
Cloudflare Access:
INTERFACE_AUTH=cloudflare
CLOUDFLARE_ZERO_TRUST_ENABLED=true
CLOUDFLARE_TEAM_DOMAIN=https://returnearly.cloudflareaccess.com
CLOUDFLARE_ADMIN_AUD=your-application-aud-tag
The origin must sit behind Cloudflare Tunnel (or equivalent). A valid Access JWT is a bearer credential.
NOMINAL_API_MANAGED=true locks monitor and notification-channel create, edit, and delete in the Filament admin. GraphQL and Sanctum tokens stay available so Terraform can manage those records. Pause, resume, and maintenance stay available in the admin.
POST /graphql with a Sanctum bearer token (php artisan nominal:token [email protected]).
mutation {
createMonitor(input: {
name: "API"
type: Http
target: "https://example.com/health"
conditions: ["[STATUS] == 200"]
}) { id }
}
[BODY] == pat(*healthy*) matches a substring in the raw response. [REDIRECT] is the Location header when follow redirects is off, or the final URL when it is on:
mutation {
createMonitor(input: {
name: "Login redirect"
type: Http
target: "https://example.com/login"
followRedirects: false
conditions: ["[STATUS] == 302", "[REDIRECT] == pat(https://example.com/app/*)"]
}) { id }
}
GraphQL monitors wrap requestBody as {"query": "..."} and default to POST:
mutation {
createMonitor(input: {
name: "Countries"
type: GraphQL
target: "https://countries.trevorblades.com/"
requestBody: "{ __typename }"
conditions: ["[STATUS] == 200", "has([BODY].errors) == false"]
}) { id }
}
Unauthenticated clients receive GraphQL errors[]. HTTP status is still 200 — Terraform maps those errors as failed applies.
Database monitors take a connection URL, log in, and run a version/status query (SHOW TABLES / public tables / Redis INFO and DBSIZE). Optional requestBody is custom SQL or a Redis command:
mutation {
createMonitor(input: {
name: "Primary Postgres"
type: Postgres
target: "postgres://monitor:[email protected]:5432/app"
conditions: ["[CONNECTED] == true", "has([BODY].version) == true"]
}) { id }
}
Notification channels take name, type, and the nested input for that type (mail, slack, microsoftTeams, discord, webhook, pagerduty):
mutation {
createNotificationChannel(input: {
name: "Ops Slack"
type: Slack
slack: { webhookUrl: "https://hooks.slack.com/services/T/B/xxx" }
}) {
id
slack { webhookUrl }
}
}
Nominal’s Filament UI is admin-only. Publish one or more public status pages (Uptime Kuma-style) instead of using the dashboard as the status page (Gatus-style).
Each page can:
Path URL: /status/{slug}. Custom domain: CNAME the hostname to Nominal; the page is served at / on that host.
GraphQL: createStatusPage, createIncident, addIncidentUpdate.
The Filament admin subscribes to live events over Reverb and refreshes when a check finishes. Tables and widgets still poll every 10s if the WebSocket is down.
Live events are broadcast on:
private-monitorsprivate-monitors.{uuid}Payloads: MonitorStatusUpdated, CheckCompleted. Authenticate /broadcasting/auth with the same Sanctum session or bearer token used for GraphQL.
Public status pages keep a meta refresh (refresh_seconds) — they are unauthenticated, so they do not use the private monitor channels.
Reverb through Cloudflare needs extra setup; GraphQL HTTP does not.
GET /metrics — Redis/cache-backed counters and gauges, prefix nominal_. Labels: monitor, type, success, region.
Public SVG and JSON badges for each monitor — the same first-class integration Gatus, Healthchecks, and Uptime Kuma expose. Served from /embed so they can be allowlisted independently of /api (e.g. through a firewall).
GET /embed/badges/{id}/status.svg
GET /embed/badges/{id}/status.json
GET /embed/badges/{id}/uptime/{period}/badge.svg
GET /embed/badges/{id}/uptime/{period}
GET /embed/badges/{id}/latency/{period}/badge.svg
GET /embed/badges/{id}/latency/{period}
Periods: 1h, 24h, 7d, 30d (any {n}h / {n}d up to 90 days). Omit the period to default to 24h. JSON is Shields.io endpoint compatible (schemaVersion, label, message, color).

Copy URLs and markdown from the monitor page.
Each probe has a queue such as checks.us-east. Workers set PROBE_REGION=us-east and listen to checks.us-east. SQLite is single-node only; use MySQL or Postgres for multiple writers.
ICMP inside Docker needs cap_add: [NET_RAW]. Ping falls back to TCP 443/80 when ICMP is blocked.
App container is serversideup/php:8.5-frankenphp running Laravel Octane (octane:start --server=frankenphp) with OPcache on. Compose (development) adds --watch plus opcache.validate_timestamps so PHP/config changes reload without rebuilding. Production image leaves timestamps off and omits --watch.
cp .env.example .env
php artisan key:generate
touch database/database.sqlite
composer install
docker compose up --build
App is on http://localhost:8000 (container port 8080). Queue, scheduler, and Reverb are the same image with command: overrides. Extra regional workers copy worker and change PROBE_REGION / --queue.
Production images (linux/amd64 and linux/arm64) are published to the GitHub Container Registry on every push to master (latest) and on version tags:
docker pull ghcr.io/returnearly/nominal:latest
The package is public. If the first publish lands as private, set visibility to Public once under the repo's Packages settings.
Copyright © 2026 Return Early.
Nominal is licensed under the Elastic License 2.0 (source-available, not OSI open source). You may self-host it and run it for your own business, including for-profit internal use. You may not offer Nominal to third parties as a hosted or managed service.