Every morning, an agent reconstructs yesterday from my Coast screen history, finds the loose ends — things I left unfinished, never sent, or forgot to follow up on — and publishes a recap page with cropped screenshot evidence. A push notification lands on my phone when it's ready. Marking an item complete on the page feeds back into the next morning's audit.
(full quality: docs/demo.mp4)
- 9:00 — launchd starts a headless OpenCode run
(
run.sh+prompt-template.md) with a random jitter. - The agent reads its memory: previous audits (
history/), the previous recap JSON, and which items I marked complete on the page (state/interactions.json). - It dispatches two subagents in parallel over the Coast CLI: one hunts communication loose ends (unsent replies, people waiting on me), the other work-in-progress loose ends (abandoned terminals, half-typed prompts, errored flows). Carryover items from previous days get re-verified against the new day's evidence.
- For the items where a screenshot helps, it locates the exact frame, crops
to the evidence region using Coast's OCR box coordinates
(
scripts/crop-evidence.py), then looks at each crop with vision and only ships images that actually show the claimed evidence. - It writes
site/data/<date>.json. The Bun server renders it as a per-day page (/july-28th-2026) with an archive at/. - A 10-minute two-way sync (
scripts/sync.sh) pushes the site to an exe.dev box (auth-gated HTTPS) and merges item interactions in both directions. The first sync after a new recap fires a Hark push notification with a tap-through to the day's page. - Tapping a row on the page blurs it and offers Mark complete — that interaction syncs back and becomes "cleared" in tomorrow's audit.
| Path | What it is |
|---|---|
run.sh |
Morning entrypoint: date substitution, jitter, headless opencode2 run --auto |
prompt-template.md |
The agent's brief: memory, subagents, synthesis rules, crop verification, output schema |
scripts/crop-evidence.py |
Frame + on-screen text → OCR-box union → padded sips crop |
scripts/sync.sh |
Two-way state merge + site push to the box + once-per-day Hark notification |
scripts/fetch-brand-assets.sh |
Pulls the Coast typeface subsets + mark from coast.app (not vendored) |
scripts/hark-icon.html |
Renders the notification icon (Chrome headless → 512px PNG) |
server/server.ts |
Bun server: static site, /api/recap/*, /api/recaps, /api/interactions |
site/index.html |
The recap UI: archive + day views, mark-complete flow, lightbox, staggered entrances |
launchd/*.plist |
The three services: 9:00 audit, persistent web server, 10-minute sync |
Machine-specific paths live in the plists, run.sh, and prompt-template.md
— adjust before use.
- Coast running with CLI access enabled (
coaston PATH). - OpenCode V2 (
opencode2) with thecoast-cli-skillskill installed globally. - Bun for the server, Node 22+ for
harkctl. scripts/fetch-brand-assets.shto pull fonts + mark.- An exe.dev box (
ssh exe.dev new) with the server under systemd; keep the HTTP proxy private. npx harkctl auth login, then bootstrap the three launchd agents.
The interesting data never leaves the machines I control, and none of it is in this repo: recap JSONs, screenshot crops, audit history, and interaction state are all gitignored. The exe.dev box is auth-gated. Review anything you generate before sharing it — screen history is the most sensitive data there is.
Coast's name, mark, and the Suisse Intl typeface belong to Attention Engineering and Swiss Typefaces respectively; this is a personal project that fetches those assets from coast.app at setup time rather than redistributing them.