Build ArtificialWatch
KINDAreplaces $19.99/mosaves $239.88/yrback to the verdict
A launch alerter whose hard problems are enumerating every model id a provider actually exposes rather than the first page of them, firing once for a real launch and never for a renamed alias, and proving to yourself that the watcher is still alive on the morning nothing has happened.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the poller and the local page in one process.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - have readya few pounds a month, or free on hardware you own
Why The product is the alert arriving at seven in the morning, which a laptop that slept cannot deliver.
Get it A small virtual server or a single-board computer at home, with a process supervisor configured to start on boot.
Verify
The watcher is running after a reboot with no manual step - API keylisting models is typically free, but check each provider's terms
Why Coverage is exactly the set of providers you hold a key for, which is the tool's main limitation and should be visible from the start.
Get it Create a read-scoped key per provider where the provider supports scoping.
Verify
Each adapter lists models and records a successful sweep - accountfree tiers are common
Why The alert has to reach a phone, and the delivery result has to be observable rather than assumed.
Get it Create a topic on a push service and subscribe your phone to it.
Verify
A test alert arrives and its delivery is recorded - accountfree tiers are common
Why Something outside the process must notice when it stops, because the failure mode of this product is silence.
Get it Any uptime checker that can call a URL or expect a periodic ping.
Verify
Stopping the process produces an external alert within the stated window - decidefree
Why These decide which ids never fire, and writing them before the first false alarm is what keeps you from muting the topic after it.
Get it List the dated snapshot, preview and moving alias shapes each provider uses, with a reason per pattern.
Verify
Each pattern is stored with its reason and visible on the suppressed list
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- providers(id, name, base_url, key_env, enabled, page_limit, last_good_sweep_at, consecutive_errors) - sweeps(id, provider_id, started_at, finished_at, pages_fetched, ids_seen, http_status, error) · one row per attempt, successful or not - model_ids(provider_id, model_id, first_seen_at, first_seen_sweep_id, confirmed_at, announced_at, suppressed_reason) - alerts(id, provider_id, model_id, created_at, delivered_at, attempts, last_error, dedupe_key) - filters(id, pattern, reason, added_at) · alias and dated snapshot patterns that never fire - heartbeats(at, providers_ok, providers_failing) · written every tick, read by whatever watches the watcher - A sweep row exists before the request is made, so a process that dies mid-sweep leaves evidence rather than a gap that looks like a quiet minute.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_PATH | required | ./data/watcher.db | Seen ids, sweeps, alerts and heartbeats. |
SWEEP_INTERVAL_SECONDS | required | 60 | One sweep per provider per tick. Check each provider's rate limits before lowering it. |
ANTHROPIC_API_KEYsecret | optional | sk-ant-...redacted | One provider adapter. Absent means that provider is listed as not covered. |
OPENAI_API_KEYsecret | optional | sk-...redacted | Another adapter, same rule about coverage. |
OPENROUTER_API_KEYsecret | optional | sk-or-...redacted | Covers models from labs you hold no direct account with. |
PUSH_TOPIC_URLsecret | required | https://ntfy.sh/your-private-topic | Treat the topic name as a secret; anyone with it can post to your phone. |
PROVIDER_ERROR_ALERT_MINUTES | required | 10 | How long a provider may error before the watcher alerts about itself. |
LAUNCH_LOG_PATH | required | ./data/launches.md | Append-only record, written even when the push fails. |
The build, in order
Every id a provider exposes, not the first page of them
Each adapter pages to the end of the list and records how many pages it read.
The default page size is the number that will embarrass you.
Files
src/providers/anthropic.jssrc/providers/openai.jssrc/providers/openrouter.jsA partial list is not a smaller list, it is a wrong one.
Files
src/sweep.jstest/pagination.test.jsOtherwise the first tick pages you about every model that exists.
Files
src/seed.js
done when · tick each as it passeswatch out- Reading the first page and assuming that is the list gives you twenty ids from a provider that has sixty, and the failure is invisible because twenty ids is a plausible answer. Worse, the day you fix the pagination forty old models arrive at once and every one of them fires as a launch. Page to the end from the first commit, and record the page count so a regression shows up in the sweep table.
A launch is an id you have never seen, twice
New ids are confirmed across two sweeps and known alias patterns never fire.
A failed sweep in between must not count as agreement.
Files
src/diff.jstest/debounce.test.jsYou will need to know why the launch you missed was filtered.
Files
src/filters.jsSilently dropped ids are how a watcher goes quietly wrong.
Files
src/web/suppressed.js
done when · tick each as it passeswatch out- Firing on the first appearance means every brief listing glitch, every regional rollout and every alias that points at yesterday's model wakes you at four in the morning, and after the second false alarm you mute the topic, which is the same as deleting the product. Confirm across two sweeps and keep suppressions visible so a wrong pattern can be found and removed.
An alert that was actually delivered
Every confirmed launch reaches the phone once, and a failed delivery is retried and visible.
The retry path is where duplicates come from.
Files
src/alert.jsAn alert you cannot prove was delivered was not delivered.
Files
src/db/alerts.jstest/delivery.test.jsThe file is the record that survives every outage.
Files
src/log.js
done when · tick each as it passeswatch out- Treating the push as fire and forget means a muted topic, an expired token or a five hundred from the notification service produces exactly the same silence as no launch, and you learn about the model from somewhere else a day later. Record the delivery attempt, retry it, and show undelivered alerts on the page.
Proving the silence is real
A quiet morning is distinguishable from a dead watcher at a glance.
The single most useful number on the page.
Files
src/web/dashboard.jsSomething outside this process has to watch it.
Files
src/heartbeat.jsGetting yourself rate limited during a launch is the wrong day for it.
Files
src/http.jstest/backoff.test.js
done when · tick each as it passeswatch out- A watcher reports nothing when everything is quiet and also when its key expired three weeks ago, and those look identical from the outside, which is how people discover at the wrong moment that their alerter died in March. Show the age of the last good sweep per provider, and make an external check on the heartbeat part of the setup rather than an optional extra.
Uptime, keys, and saying what you cannot seeproduct builder
The watcher survives reboots and states plainly which labs it covers.
Supervisor configuration that has never been tested is decoration.
Files
ops/supervisor.mdThe seen-id table is the only thing that stops a replay of every launch.
Files
src/providers/keys.jsSo the gap travels with the message rather than living in a README.
Files
src/alert.js
done when · tick each as it passeswatch out- Claiming to watch for new models while only holding keys for two providers means the first thing the tool misses is the launch you cared most about, from a lab you never had an account with. Print the covered and uncovered list on the page and in the alert footer, so the boundary travels with every message.
That is the whole plan for ArtificialWatch. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Phone calls and text messages.
- A pre-launch watchlist.
- Blog and pricing page scraping.
- Launch day benchmark scores.
- coverage of labs you hold no key for · 48 tracked models including Chinese labs and restricted previews
- the phone call that rings until you answer, and SMS · Twilio plus US A2P 10DLC registration
- the pre-launch watchlist and live Polymarket odds on models that have not shipped, which no API can return
- debounce and alias filtering tuned so dated snapshots and -preview ids do not fire false alarms
- someone else owning the uptime · your poller sleeps when your machine does
- A second push destination, so a muted topic is not a single point of failure
- Context enrichment from an open model database, kept clearly separate from what the provider returned
- A weekly digest of suppressed ids, which is how you find a pattern that is filtering too much
Need the files? The project pack on the verdict page hands your agent the whole brief · more rss & research.