Build ArtificialWatch

KINDAreplaces $19.99/mosaves $239.88/yrback to the verdict

0%0 of 18 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

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.

estimated effort weekendthe files for this build are in the project pack

RuntimeNode.js 22, one process under a supervisor on an always-on machineScheduleA cron tick at a fixed interval, with one sweep per provider per tickStoragebetter-sqlite3 holding every id ever seen and every sweep attemptedProvidersOne adapter per provider, each paging to the end of its listAlertingA push topic with a delivery check, plus an append-only launch log

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. 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

  2. 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

  3. 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

  4. free 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

  5. free 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

  6. 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.

VariableNeededExampleWhere the value comes from
DATABASE_PATHrequired./data/watcher.dbSeen ids, sweeps, alerts and heartbeats.
SWEEP_INTERVAL_SECONDSrequired60One sweep per provider per tick. Check each provider's rate limits before lowering it.
ANTHROPIC_API_KEYsecretoptionalsk-ant-...redactedOne provider adapter. Absent means that provider is listed as not covered.
OPENAI_API_KEYsecretoptionalsk-...redactedAnother adapter, same rule about coverage.
OPENROUTER_API_KEYsecretoptionalsk-or-...redactedCovers models from labs you hold no direct account with.
PUSH_TOPIC_URLsecretrequiredhttps://ntfy.sh/your-private-topicTreat the topic name as a secret; anyone with it can post to your phone.
PROVIDER_ERROR_ALERT_MINUTESrequired10How long a provider may error before the watcher alerts about itself.
LAUNCH_LOG_PATHrequired./data/launches.mdAppend-only record, written even when the push fails.

The build, in order

  1. 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.

    1. The default page size is the number that will embarrass you.

      Files src/providers/anthropic.jssrc/providers/openai.jssrc/providers/openrouter.js

    2. A partial list is not a smaller list, it is a wrong one.

      Files src/sweep.jstest/pagination.test.js

    3. Otherwise the first tick pages you about every model that exists.

      Files src/seed.js

    done when · tick each as it passes
    watch 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.
  2. A launch is an id you have never seen, twice

    New ids are confirmed across two sweeps and known alias patterns never fire.

    1. A failed sweep in between must not count as agreement.

      Files src/diff.jstest/debounce.test.js

    2. You will need to know why the launch you missed was filtered.

      Files src/filters.js

    3. Silently dropped ids are how a watcher goes quietly wrong.

      Files src/web/suppressed.js

    done when · tick each as it passes
    watch 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.
  3. An alert that was actually delivered

    Every confirmed launch reaches the phone once, and a failed delivery is retried and visible.

    1. The retry path is where duplicates come from.

      Files src/alert.js

    2. An alert you cannot prove was delivered was not delivered.

      Files src/db/alerts.jstest/delivery.test.js

    3. The file is the record that survives every outage.

      Files src/log.js

    done when · tick each as it passes
    watch 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.
  4. Proving the silence is real

    A quiet morning is distinguishable from a dead watcher at a glance.

    1. The single most useful number on the page.

      Files src/web/dashboard.js

    2. Something outside this process has to watch it.

      Files src/heartbeat.js

    3. Getting 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 passes
    watch 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.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more rss & research.