# Changelog: the app's scope, and what it asks of the API A scope for Jamie's review, 2026-10-29, written to test the v1 API in `CHANGELOG-API-PLAN.md` against a real client. Nothing is built. Facts were checked against `origin/main` at fb92ff8, read-only. Jamie, 2026-10-29: Changelog is "a super efficient way to send events into release notes", and the v1 API is "adding content", with Upcoming "supported as well. That is a great feature that could then power notifications." ## What Changelog is A capture tool with four verbs: **log** a note, **plan** a date, **get reminded**, and **check** what happened. It is not a reader of your notes. The web app is where you read, search, look back and change settings. Jamie, 2026-10-29, on the fourth: "showing recent activity would be a good thing in there too, because it's a way to confirm what did the app do and what did other entities do. That would also potentially allow us to hook in notifications on the activity feed." - **Open to typing.** The keyboard is up when the app opens. Typing and sending a line takes two taps. - **Never lose a note.** Everything goes through an offline queue and is sent when the phone can, without making duplicates. - **Tags are one tap.** Pinned tags, recent tags, and a sticky tag that stays on for a trip. - **The software metaphor,** in small doses: today's version in monospace at the top, "Filed in 5.4.278", an empty state of "No changes yet in 5.4.278". - **Never reads your words.** Changelog asks for `notes:write`, `media:write`, `upcoming` and `activity`, never `notes:read`. The activity it reads says what happened, through what, and on which day, never what a note said (see Activity, below). A lost phone or a leaked token can add to your notes and see that things happened, but can't read them. ## Screens **1. Log (the home screen)** ``` 5.4.278 12-day streak ───────────────────────────────────────────────────── | Fixed the kitchen faucet, finally. | | | ───────────────────────────────────────────────────── #house #work #kids #running + sticky: none [photo] [camera] [voice] [here: Saint Paul] [Commit] Filed in 5.4.278 · 9:41 "Ran the river loop #running" Added by Claude · 8:15 a note in 5.4.278 Reply filed · 6:52 your email to 5.4.278 Filed in 5.4.278 · 7:02 "Coffee with [name]" (words: this phone's own) ``` - The header is today's version and the streak, or "Nothing yet in 5.4.278". - The tag row has pinned tags first, then recent ones. A long press makes a tag sticky until you turn it off. - Attach a photo, take a picture, or record a voice memo. "Here" adds the phone's spot and can offer a nearby business, as the web's Here does. - Below is today's activity, from every channel: "Filed in 5.4.278 via Changelog", "Reply filed", "Added by Claude". What this phone has queued shows as waiting. Swipe to edit or delete a note Changelog wrote. - A badge earned by the note shows as a short toast, only while "Show badges" is on. - The button's word is Jamie's to pick: "Commit", "Ship", or a plain "Add". **2. Upcoming** - The list of dates, each with the server's own line ("Mom turns 7.0.0. A major release.", "Maine. June 14 - 21."). - Add or edit: kind (birthday, anniversary, trip, event), title, the date, the year if known, an end date for a trip, a destination typed as text, a tag, and the reminder days (7, 1 and 0 by default; 14, 1 and 0 for a trip). - Delete. **3. Activity** - The activity log, newest first, from every channel, each row saying when, through what (email, the web, Changelog, Terminal, Claude), what happened and on which day. Tap a note row to open that day on the web. - A "since you last looked" line. The phone keeps that marker itself, so the server stores nothing new. - Filter by kind: notes, email, badges, Upcoming, connections, problems. **4. Settings** - Which connection this is ("Changelog on Jamie's iPhone"), and Sign out, which revokes the token. - Notifications: Upcoming reminders, activity, and the daily prompt. - Pinned tags, and whether Here is on by default. - Links out: Open Release Notes, the guide, and `/delete/`. **5. Everywhere else** - **Share extension:** a short Log sheet holding whatever was shared (a link, a photo, some text), with the tag row. - **Widgets:** small (version and streak); medium (version, a Log button, the next Upcoming line); Lock Screen (the version, inline). - **App Intents:** "Add to Changelog" in Siri and Shortcuts, the Action Button, and a Control Center control. - **Apple Watch** dictation, later. ## Notifications, with no push server Every notification is local: scheduled by the app on the phone, from data it fetched. Release Notes keeps no device tokens and no Apple push key (a secret it would otherwise have to hold), and notifications still fire when the phone is offline. - **Upcoming reminders.** On each reminder day, at the account's send time, with the same line the email carries that morning. The server works out which reminders fall on which days, so the leap-day rule and the reminder days live in one place, and the Android app can't get them wrong either. - **The daily prompt** (optional, call 3). "You're 5.4.278 today. What changed?" at send time, which opens Log. - **A rolling window.** iOS keeps at most 64 pending notifications an app, so the app schedules about 14 days ahead and tops up whenever it opens and in background refresh. - **Activity notifications** (off until turned on in the app). Each kind is chosen in the app's settings: - notes added by someone else: an agent, another token, an import, or an email reply when you're away from the phone; - problems: an email that wasn't filed, the account stopped, a connection ended; - badges earned. Never your own notes from this phone, and never the daily email going out. They come from background refresh, so iOS decides when. That might be minutes or hours, not instant. Instant would need real push (see below). - **Real push, later.** Apple push needs the paid Developer Program, an APNs key (a secret Jamie would keep), device tokens stored per account, and a worker on the table's stream sending them. That is its own design, like webhooks. Nothing in v1 blocks it: activity rows are already in the table, and the stream already exists. - **The rule this changes.** AGENTS.md says Upcoming reminders "travel only in the daily email", and the calendar link carries "no alarms". Phone notifications would be a second channel: chosen on that phone, carrying the email's own lines, and with no extra email. AGENTS.md would record it with Jamie's words (call 2). ## Checking the API against the app Each thing the app does, the call it needs, and what that changes in the plan. | The app | Call | Against the plan | |---|---|---| | Version, streak, "nothing yet" | `GET /v1/me` | **Changed:** add `wrote_today`, `streak`, `send_time`, `tz`, `paused_until` and `status` | | Widgets and notifications that fire offline | `GET /v1/me` `days` | **New:** the next 14 days, each with its version. Clients never port the version arithmetic, and the birthday is never sent | | A text note | `POST /v1/notes` | **Changed:** takes `written_at`, the moment it was typed. A note queued at 11:58pm and sent at 12:05am files to the day it was written (the account's local day), unless `date` says otherwise | | Safe retries | `Idempotency-Key` | **Changed:** receipts last 24 hours today, which a phone offline over a weekend can outlast. Keep them 7 days on `/v1` | | The tag row | `GET /v1/tags` | **Changed:** the pinned list first, then the tags used most in the last 30 days, with counts and last use | | Pinned tags | `PUT /v1/tags/pinned` | **New,** if pins live on the account (call 4) | | Sticky tag | none | the app keeps it | | Photos, camera, voice | `POST /v1/uploads`, then the note names its uploads | **Changed:** see "Files", below. The one infra change | | Here | `POST /v1/places/here` `{lat, lon, accuracy_m}` | **New to v1,** as the web's: the spot, its neighbourhood and up to six nearby businesses | | A city typed by hand | `GET /v1/places?q=` | **New to v1,** the web's city search | | Edit or delete a note sent today | `PUT` and `DELETE` on its own notes, with `revision` | as planned | | Badge toast | `unlocked` in the create answer | as planned | | Upcoming list, add, edit, delete | `GET /v1/upcoming`, `POST /v1/upcoming/batch`, `DELETE` | **New to v1** (Jamie). MCP's rules carry over: a revision on every change, `dry_run`, all or nothing, 50 writes a day, the `upcoming` scope | | Reminder notifications | `GET /v1/upcoming/reminders?days=14` | **New:** each day's due reminders with the email's own `line` and `when` | | Sign out | `DELETE /v1/token` | **New:** a token can revoke itself | | Today's list and the Activity screen | `GET /v1/activity?after=&kinds=` | **New** (Jamie). The log as MCP's `notes_activity` reads it, minus anything that carries words: no email subjects, words or other senders' addresses, and settings changes name the field without its old and new values. Upcoming titles only with `upcoming`. A new `activity` scope | | Activity notifications | `GET /v1/activity` with the last cursor seen | **New:** the same call, from background refresh | | Stopped, deleting, revoked, over the limit | errors | **Changed:** one error shape with a code (`token_revoked`, `account_stopped`, `scope_required`, `rate_limited`) and `Retry-After` on 429 | | A shared link | the note's text | as planned; the server fetches its title once | | Siri, Shortcuts, the Action Button | App Intents calling `POST /v1/notes` | as planned | **Reading the archive left v1.** Nothing in Changelog reads past notes, and Jamie made content and Upcoming the v1 API. The read endpoints in the earlier draft move to "later, if wanted". ### Files This is where the app pushes the API hardest. - MCP takes files as base64 in the call: at most 4 files and 4 MB together, because a synchronous Lambda invoke carries 6 MB. A phone photo or a five-minute voice memo can be that size alone. - The web uses signed upload forms instead: 50 MB a file, 20 files a note, 200 uploads and 2 GB a day per account. `/v1` should use those too. - **Infra change, flagged.** The signed forms and the attach step that follows them run in the web server today, under a session. The token server's roles were built without upload rights. Phase 3 needs the token server, or its capture function, to sign forms for the pending prefix and run the same attach, with the same checks. That is a role change in the stack. - A form lives five minutes, but a background upload on a weak signal can start later than that. Either the app asks for the form just before it uploads, or `/v1` forms last longer (30 minutes). *Recommend the app asks late,* with no change to the server. - **HEIC never reaches the email.** iPhone photos are HEIC, and a HEIC gets no thumbnail (AGENTS.md, Thumbnails), so it never appears in the morning email. A native app sends whatever it's given. I haven't checked whether the web's picker gets JPEG or HEIC from an iPhone. Its accept list names HEIC, so web uploads may be HEIC too. Either Changelog asks the photo picker for its "compatible" JPEG (place and time kept), or the server learns to make HEIC thumbnails (call 1). ## Android, for [a cousin] Nothing above is iPhone-only on the API side. Each piece has an Android match: WorkManager for the queue, local notifications on a schedule, Glance widgets, a share target and a Quick Settings tile. The `days` and `reminders` answers mean [the Android app's builder] never writes the version arithmetic or the reminder rules in Kotlin. The only platform-specific server work is the OAuth callback, which the API plan already covers. ## Versions of the app | Version | Adds | Needs (API plan) | |---|---|---| | **0.1** | Log with text and the tag row, the version header, the offline queue, today's activity with edit and delete, the Activity screen, sign-in by token | phase 1 | | **0.2** | photos, the camera, voice, Here, the share extension | phase 3 | | **0.3** | the Upcoming screen, reminder and activity notifications, the optional daily prompt | phase 4 | | **0.4** | App Intents, the Action Button, the control and widgets | nothing new | | **1.0** | OAuth sign-in, the App Store | phase 5 | ## The tag row on the web too Jamie, 2026-10-29: "That could also come into the web interface." The same row goes on the web's Today form: pinned tags, recent ones, a sticky tag. That is the strongest reason to keep pins on the account instead of on each phone (call 4). The sticky tag stays on each device, since it's a habit of the moment, not a setting. ## Jamie's calls Answered 2026-10-29: 1. **HEIC photos:** Changelog sends the picker's JPEG, with place and time kept ("Fine with this"). Still worth checking whether iPhone uploads on the web arrive as HEIC. 2. **Reminders on the phone: yes.** Jamie: "Reminders are going to show up in other places. The daily email is already doing too much work." That reaches past Changelog: the AGENTS.md rule becomes "reminders can travel in any channel the owner turns on", not "only in the daily email". 3. **The daily prompt** is off by default ("Sure"). 4. **Pins: yes.** Jamie: "Pinned tags are good and then also augmented with frequently used RECENT tags." The row is your pinned tags first, then the tags you've used most in the last 30 days. Pins live on the account, so the web's Today form and every phone show the same ones, set from either through `PUT /v1/tags/pinned`. That is the one narrow exception to "settings change only on the web". The sticky tag stays on each device. 5. **Idempotency receipts kept 7 days on `/v1`:** stated in the summary, with no objection. 6. **The Apple Developer account** is Jamie's own, under [email address removed], signed in to Xcode on this Mac (Jamie, 2026-10-29). It is **not yet in the paid Developer Program**. Enrolling ($99 a year, as an individual, so the App Store shows Jamie's own name as the seller) is needed for TestFlight and the App Store, not to start. Until then, Xcode can put a build on Jamie's own iPhone with the free account. Such a build stops working after about a week, and some capabilities need the paid program. Enrol once 0.1 is worth carrying around. 7. **Names:** the Log button's word (Commit, Ship or Add) and the two Firsts. Open. 8. **Activity in the app (Jamie, 2026-10-29).** - The feed reads a trimmed log under a new `activity` scope. It leaves out email subjects, email words, other senders' addresses and old and new settings values. *Recommend this,* so "never reads your words" stays true. - Activity notifications are off until turned on, then cover others' notes, problems and badges, from background refresh. *Recommend this.* - Real push is a later design of its own. *Recommend deferring it.*