A Clark View source that reminds to give flea medication on the 8th of every month, and nothing else. Every row carries the same fixed text.
Built on the shared source SDK:
protocol v1 over rpc.ts, bearer-authenticated, SQLite owned by this val.
AGENTS.md owns the add-entry: shortcut for individual custom events,
including normalization, conflict handling, and transactional verification. Update
it alongside changes to storage or reader selection. It uses direct SQLite access;
it is separate from the authoritative monthly reminders.rebuild operation.
Unlike Moon/Lunar, which store a JSON payload column and derive display
text in code, flea_medication_reminders stores main_text and sub_text
as real columns — every row's reminder text is identical, so there is
nothing a payload blob would buy here:
CREATE TABLE flea_medication_reminders(
date_key TEXT PRIMARY KEY,
main_text TEXT NOT NULL,
sub_text TEXT NOT NULL,
starts_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL,
fetched_at TEXT NOT NULL
)
The existing database received an additive nullable expires_at INTEGER column;
all existing rows were backfilled with starts_at + 3600. New databases use the
NOT NULL schema above. Every write must supply expiry; missing/invalid windows
are rejected by the SDK on read. Reads never migrate storage.
| File | Role |
|---|---|
lib/schedule.ts | Pure arithmetic: monthly date generation, noon-in-zone-to-UTC conversion. No storage, clock or network. |
gtbSource.ts | Source definition, offset policy, item text, flea_medication_reminders storage and rebuildSchedule. |
rpc.ts | HTTP entry: bearer authentication around serveSource. |
check.ts | Contract, schedule, DST, offset, protocol, auth and storage checks. Disposable rows are removed. |
Settings are exactly {} — there is nothing to select, and the parent's
browser form renders no controls. One item is returned: the next reminder
on or after the reader's current civil date.
{ "id": "gtb-2026-10-08", "mainText": "Give Flea medication", "subText": "Gemma, Bron, Tilka 🐈🐈⬛🐈", "caption": null, "emphasized": false, "startsAt": 1791486000, "expiresAt": 1791489600 }
(noon Pacific on 2026-10-08, stored as 19:00 UTC — PDT is in effect that date)
startsAt (stored in starts_at) is Unix seconds for local noon in America/Los_Angeles on the
reminder date, precomputed and stored in UTC at write time — it does not
depend on the reader's timezone. caption is null, unlike Moon's PEAK or
Lunar's DAY 15: noon Pacific is the actual reminder instant here, not a
whole-day or astronomical event, so the widget renders it as a real clock
time in the reader's own zone. expiresAt is stored in expires_at, exactly one
hour after the start for rebuilt reminders. It controls lifecycle and refresh timing
and is never displayed. The source uses SDK snapshot 12-main and emits no legacy
wire timestamp; the parent owns compatibility for older clients.
utcOffsetSeconds: null (used only to pick the reader's "today" for
selecting the next row) falls back to America/Los_Angeles, matching
Moon/Lunar.
The write operation reminders.rebuild replaces the next count monthly
reminders authoritatively, starting after after (YYYY-MM-DD):
{ "protocolVersion": 1, "sourceKey": "gtb", "operation": "reminders.rebuild", "payload": { "count": 12, "after": "2026-09-09" } }
The initial 12 months (2026-10-08 through 2027-09-08) were seeded this way at
deployment. There is no automatic reseed job — unlike Lunar's annual interval,
this schedule is a fixed formula with nothing upstream to poll for, but it
still needs a fresh reminders.rebuild call with a later after date before
the stored window is exhausted. Add an interval later if ongoing unattended
extension is wanted; it was left out here as unbuilt scope, not an oversight.
- Set
SOURCE_GTB_V1_TOKENon this val. - Register in
plusjade/app-clarkview:rpc.ts's endpoint, source keygtb, protocol version 1, and a credential reference holding the same bearer value configured independently in the parent. Then assign it to a device. - Run
check.tsafter any change. With the token set it also covers the authenticated mount; without it, everything but that one assertion still runs. - Run
http-check.tsafter merging to verify the deployed authenticated descriptor and nonempty window feed at null and extreme timezone offsets.