# Reminder ↔ Note Linking — Build Spec

> **STATUS: BUILT AND VERIFIED CROSS-PLATFORM, 2026-07-02.** All tests pass on
> macOS 15 (Sequoia): failure path (bogus token → alert), success path (token →
> note opens), full round trip (reminder URL chip → Shortcuts → correct note).
> **iOS confirmed same day** — the same reminder's URL chip opens the note on
> iPhone after iCloud sync. No permission prompts on either platform. The
> system is live.

A cross-platform (macOS + iOS/iPadOS) system for linking an Apple Reminder to an
Apple Notes note, using a **timestamp token** stored in the note title and a
`shortcuts://` relay URL stored in the reminder's URL field.

Two Shortcuts do the work:

- **`CreateNoteLink`** — creates a token-tagged note from a plaintext template
  and puts a relay URL on the clipboard for you to paste into the reminder.
- **`OpenLinkedNote`** — invoked by that relay URL; finds the note by token and
  opens it.

This is deliberately *not* the "elegant deep link" approach — those don't exist
cross-platform (see [Design rationale](#design-rationale)). This trades a direct
link for something fully buildable on both platforms with no private APIs.

---

## Why this shape (the constraints that forced it)

Three hard walls, confirmed in the research thread
(`How do I create a link between an Apple Reminders.md`) and — where marked —
tested directly on this machine:

1. **The Reminder URL field is closed to automation.** AppleScript can neither
   write nor read it (**tested here** — see [Verified findings](#verified-findings)),
   and EventKit/Shortcuts can't read it. → Any token you want to read later must
   live somewhere readable. Here it lives in the **note title**; the URL field
   holds only the fire-and-forget relay URL, pasted by hand.
2. **No cross-platform "open this note" URL exists without the Share Sheet.**
   `applenotes:note/<UUID>` is macOS-only; the `https://www.icloud.com/notes/…`
   URL is cross-platform but only obtainable through the collaboration Share
   Sheet UI (no API). → We avoid note URLs entirely and **search by token**.
3. **Shortcuts cannot write an existing reminder's URL field**, and Reminders
   exposes no per-reminder Share Sheet / "current reminder" action. → The one
   manual step is **you paste the relay URL** into the reminder.

The **token is a timestamp** (`RN_yyyyMMddHHmmss`), not a running counter:
no counter note to maintain, effectively collision-free, self-delimiting (so
`Name contains` search can't mis-match a prefix the way `RN_42` matches
`RN_420`), and loosely human-readable.

---

## One-time setup

1. **Notes:** create a folder named **`ReminderNotes`** (or use another name —
   set the same name in `CreateNoteLink`'s **Create Note** step, A13).
2. **Template:** put `reminder-note-template.txt` (in this repo) into
   **iCloud Drive → Shortcuts/**. It **must** be in iCloud Drive, not "On My
   Mac", so both platforms can read it. The repo copy is the source of truth;
   the iCloud copy is the working copy.
3. Build the two Shortcuts below. Action names are the search terms to type in
   the Shortcuts action library.

> **Naming warning:** every relay URL you paste embeds the name `OpenLinkedNote`.
> **Never rename Shortcut B** after you start using it — renaming breaks every
> link already stored in a reminder. Pick the name now and leave it.

---

## Spec conventions & verified UI mechanics

**`«name»` in a Config cell means "insert that variable here"** — it is never
text you type. Everything else in a Config cell is typed literally, **without
quotes** (prompts, URLs, find/replace strings). Literal square brackets `[ ]`
*do* get typed — they're part of the note-title format.

**Inserting a variable — per
[Apple's docs](https://support.apple.com/guide/shortcuts-mac/use-variables-apdd02c2780c/mac)
(authoritative, verified):**

> "Control-click in any text field in an action, then choose Insert Variable >
> Select Variable" → "Click the Magic Variable (the blue token under an action)
> that you want to add to the text field."

Plain-clicking or typing a variable's name does **not** surface a picker.
Example: the Text action reading `RN_«stamp»` is built by typing `RN_`, then
Ctrl-click → Insert Variable → Select Variable → click the `stamp` token.

**In the Select Variable view** (screenshot-verified): blue tokens appear
*between* the actions, each one directly beneath the action that produces it.
Pick by **position under the source action** — labels follow the action's name
(e.g. Ask for Input's output token is labeled "Ask for Input" on Sequoia, not
"Provided Input" as Apple's guide calls it).

**Magic variables & Set Variable:** every action's output is automatically a
magic variable named after the action ("Formatted Date", "Text", "Note"…).
Because this build has *two* Format Date and *two* Text actions, identically
named outputs would be ambiguous — so the design uses **Set Variable** actions
to give the important outputs unique names (`stamp`, `datePretty`, `noteTitle`,
`key`, `token`). Set Variable's `to` slot auto-fills with the previous action's output
(per Apple's docs); verify it shows the right source before moving on.

**Screen-verified UI facts (not in Apple's docs; confirmed on this Mac,
Sequoia/macOS 15):**

- **Format Date** has ONE format dropdown (Short/Medium/Long/Custom/…); choosing
  **Custom** reveals a format-string field and a **Locale** field (leave
  `Default`). There are no separate Date-Format/Time-Format selectors.
- **Date** outputs the current date/time by default with nothing to configure
  (don't switch it to "specified date").

**Not yet screen-verified** (flagged inline where it matters): whether Create
Note shows a separate Title field, and Find Notes' exact filter UI.

---

## Shortcut A — `CreateNoteLink`

Run it however is convenient: macOS menu-bar item, or iOS widget / Action button
/ Spotlight. It does **not** need the reminder as input.

> In the shortcut's Details/Information pane, leave **"Show in Share Sheet"
> OFF**. CreateNoteLink runs standalone and creates a *new* note, so it never
> receives shared input.

No Date action is needed: both Format Date steps use the built-in
**Current Date** *special variable* directly (insert via the same
Ctrl-click → Insert Variable menu).

| # | Action | Config | Output |
|---|--------|--------|--------|
| A1 | **Format Date** | date = «Current Date» (special variable); format **Custom**; string `yyyyMMddHHmmss`; Locale Default | Formatted Date |
| A2 | **Set Variable** | name `stamp`; to = «Formatted Date» (auto-fills from A1) | `stamp` |
| A3 | **Format Date** | date = «Current Date» (special variable); format **Custom**; string `MMM d, yyyy h:mm a` (→ `Jul 2, 2026 2:33 PM`); Locale Default | Formatted Date |
| A4 | **Set Variable** | name `datePretty`; to = «Formatted Date» (from A3) | `datePretty` |
| A5 | **Text** | type `RN_` then insert «stamp» | Text |
| A6 | **Set Variable** | name `token`; to = «Text» (from A5) | `token` |
| A7 | **Ask for Input** | type **Text**; prompt: Note title? (typed without quotes); Default Answer blank; Allow Multiple Lines OFF | Ask for Input |
| A8 | **Set Variable** | name `noteTitle`; to = «Ask for Input» (the blue token under A7 — **not** the yellow Text token; see trap below) | `noteTitle` |
| A9 | **Get File from Folder** | Folder = iCloud Drive → Shortcuts; File Path `reminder-note-template.txt`; Error If Not Found ON. (Sequoia has no plain "Get File" action — screenshot-verified) | File |
| A10 | **Replace Text** | find `{{TITLE}}` → «noteTitle»; input = «File» (from A9); Regular Expression OFF | Updated Text |
| A11 | **Replace Text** | find `{{DATE}}` → «datePretty»; input = «Updated Text» (from A10); Regular Expression OFF | Updated Text |
| A12 | **Replace Text** | find `{{TOKEN}}` → «token»; input = «Updated Text» (from A11); Regular Expression OFF | Updated Text |
| A13 | **Create Note** | reads "Create note with `Contents` in `Folder`" (screenshot-verified). Contents = «Updated Text» **from A12, the last Replace**; folder `ReminderNotes`; **Name** = «noteTitle» + space + «token» (delimiter brackets optional); Open When Run ON while testing | Note |
| A14 | **Text** | type `shortcuts://run-shortcut?name=OpenLinkedNote&input=text&text=` then insert «token» | Text |
| A15 | **Copy to Clipboard** | input = «Text» (from A14) | |
| A16 | **Show Notification** | type `Copied — paste into the Reminder URL field: ` then insert «token» | |

> **Recurring trap (hit twice during the build):** when inserting a variable,
> the picker makes A5's **Text** output (yellow icon) easy to grab by mistake.
> Verify by icon and position: «Ask for Input» is the blue token directly under
> **Ask for**; anything yellow is the Text action. If a slot that should hold
> the title shows a yellow token, it's wrong.

Result: a note titled `Renew passport [RN_20260702143305]`, and the relay URL on
the clipboard.

**About A13 (Create Note title) — resolved by test run:** Sequoia's Create Note
has a **Name** field; the Name becomes the note title and the Contents render
below it. The token must be in the Name because Shortcut B's Find Notes matches
on Name. First test run confirmed a `{{TITLE}}` first line in the template
duplicates under the title — so the template no longer has a title line; it
starts at `Created:`. The `{{TITLE}}` placeholder is no longer used by the
template (A10's Replace is now a harmless no-op; it can be deleted from the
shortcut or left in place in case the template ever wants `{{TITLE}}` back).

**Optional — pull the title from a reminder instead of typing it** (both
platforms): replace A8 with `Find Reminders` (Is Completed = false, in a chosen
list) → `Choose from List` → `Get Name`, then point A8's Set Variable
`noteTitle` at that output. One extra tap at runtime, no typing.

---

## Shortcut B — `OpenLinkedNote`

Invoked by the relay URL; the `…&input=text&text=<token>` parameters arrive as
**Shortcut Input**. The If/Otherwise wrapper (B1–B6) is only there so you can
also run it by hand and type a token — both branches must store into `key`.

A **Receive** header action appears at the top once the shortcut accepts input
(screenshot-verified on Sequoia): *"Receive `Text and Apps` input from
`Nowhere` — If there's no input: `Continue`"*. The setting that matters is
**If there's no input: Continue** — anything else (Stop / Ask) would kill the
manual-run branch before the If executes.

| # | Action | Config | Output |
|---|--------|--------|--------|
| B0 | **Receive** (header) | Text and Apps input; **If there's no input: Continue** | Shortcut Input |
| B1 | **If** | «Shortcut Input» *does not have any value* | |
| B2 | · **Ask for Input** | type **Text**; prompt: Token? (typed without quotes); **Allow Multiple Lines OFF** (a stray newline would break the Find filter) | Ask for Input |
| B3 | · **Set Variable** | name `key`; to = «Ask for Input» | `key` |
| B4 | **Otherwise** | | |
| B5 | · **Set Variable** | name `key`; to = «Shortcut Input» | `key` |
| B6 | **End If** | | |
| B7 | **Find Notes** | renders as "Find `All Note` where" (screenshot-verified); filter row: Name *contains* «key»; Sort by None; **Limit ON, Get 1** | Notes |
| B8 | **If** | input = B7's result (auto-fills; may display as «Name» — Shortcuts coerces the found note to its Name property, functionally equivalent); condition *does not have any value* | |
| B9 | · **Show Alert** | type `No note found for ` then insert «key»; Title blank; Show Cancel Button OFF | |
| B10 | **Otherwise** | | |
| B11 | · **Open Note** | renders as "Open «Note»" — target = B7's found note (auto-fills) | |
| B12 | **End If** | | |

---

## The stored link

What you paste into the reminder's **URL field** (from the clipboard, after
running CreateNoteLink):

```
shortcuts://run-shortcut?name=OpenLinkedNote&input=text&text=RN_20260702143305
```

Tapping it on iOS or macOS opens Shortcuts briefly (~1–2 s), which runs
`OpenLinkedNote`, finds the note whose title contains the token, and opens it.

No URL-encoding is needed: the token is only `RN_` plus digits, and the shortcut
name has no spaces. (If you ever change either to include spaces or symbols,
they must be percent-encoded — simpler to just not do that.)

---

## Design rationale

Condensed from the research thread. Approaches ruled out and why:

| Approach | Ruled out because |
|---|---|
| iCloud `https://www.icloud.com/notes/…` URL | Cross-platform, but only obtainable via Share Sheet UI — no API, fragile to script |
| `applenotes:note/<UUID>` | macOS only; does nothing when tapped from a reminder on iOS |
| Read deep link back out of the reminder | URL field is closed to every API (write **and** read — tested); the Share Sheet's Notes-icon link isn't in the URL field at all |
| Running counter (`RN_42`) | Needs a persistent counter note; substring search mis-matches (`RN_42` ⊂ `RN_420`); harder to generate reliably |
| Hookmark / ProNotes | macOS-only; don't bridge to iOS |
| `mobilenotes://showNote?identifier=` | Undocumented, not cross-platform-reliable |

**Kept:** timestamp token in the note title + `shortcuts://` relay. Fully
cross-platform, no private APIs, no Share Sheet, survives device sync (both
Shortcuts and Notes sync via iCloud).

---

## Known limitations

- **One manual paste** per link (the URL field), by design.
- **No Note → Reminder back-link.** Cross-platform reminder deep links don't
  exist. Mitigation: the template records the reminder's name/list as plain text
  so you can find it by hand.
- **Relay opens Shortcuts first**, then Notes (~1–2 s). Unavoidable cost of the
  relay pattern.
- **iCloud sync latency:** a note made on the Mac may not be findable on the
  iPhone until Notes syncs; `OpenLinkedNote` will show "not found" until then.
- **Orphans:** deleting the note leaves a dead URL in the reminder (handled
  gracefully by the not-found alert); deleting the reminder orphans the note
  (find it later by searching `RN_` in the `Reminder Notes` folder).
- **Editing the note title is safe** as long as the `[RN_…]` token stays intact.
- **Never rename `OpenLinkedNote`** — see warning under One-time setup.

---

## Verified findings

- **AppleScript cannot write OR read a reminder's `url`** — tested with
  `test-reminder-url.applescript` on macOS 15 (2026-07-02): write fails with
  -10006, read with -1700. The property is in the dictionary but inert. So
  manual paste is the path on both platforms; the source research thread's
  claim that `set url` works write-only is **wrong**.
- **Variable insertion is Ctrl-click → Insert Variable → Select Variable**
  (Apple docs, quoted above). Typing a variable name does nothing.
- **Format Date layout** — single format dropdown; Custom reveals format string
  + Locale (screenshot-verified).
- **Reminder URL field accepts any scheme** including `shortcuts://` (per the
  research thread; will be re-confirmed at first end-to-end test).

## Open questions — verify on device as we reach them

1. ~~Create Note: separate Title field?~~ **Answered: yes** — Sequoia's Create
   Note has Name, Contents, Folder, and Open When Run. ~~Duplicate first line?~~
   **Confirmed on first test run** — template title line duplicated under the
   Name; template updated to drop its title line (starts at `Created:`).
2. **Find Notes filter UI** for B7 — exact wording of the Name-contains filter.
3. **Exact action names** drift across OS versions — confirm `Create Note`,
   `Find Notes`, `Open Note` as you reach them. (~~`Get File`~~ resolved: it's
   **Get File from Folder** on Sequoia.)

## Build log

- **2026-07-02** — Walkthrough in progress with Claude. Built so far:
  CreateNoteLink A1 (Date), A2 (Format Date, custom `yyyyMMddHHmmss` —
  screenshot-verified), A8 (Ask for Input) partially discussed. Next: add Set
  Variable actions A3/A5/A7 and the second Format Date A4. AppleScript URL-field
  probe run and negative. Template updated to put token in first line.
- **2026-07-02 (later)** — Get File resolved: Sequoia has no "Get File" action;
  it's **Get File from Folder** (screenshot-verified). Built and confirmed
  (folder Shortcuts, path `reminder-note-template.txt`, Error If Not Found ON;
  options under "Show More/Show Less").
- **2026-07-02 (later still)** — Full-shortcut screenshot review: A1–A7 built
  correctly. **Steps renumbered:** inserted Set Variable `noteTitle` as A9
  (holds Ask for Input's answer; motivated by a real mis-pick — the first
  Replace Text's "with" slot had grabbed A6's Text output instead of Provided
  Input). Fixes applied on device: delete a stray unnamed Set Variable after
  `datePretty`; re-point Replace's "with" to «noteTitle»; verify A4's date
  token = Current Date. Next: finish A11, then A12–A13 Replaces, then A14
  Create Note (answers the Title-field open question).
- **2026-07-02 (evening)** — User dropped the standalone Date action; both
  Format Dates now use the **Current Date special variable** directly —
  correct, spec renumbered to A1–A16. Screenshot review: everything built
  through A10 (first Replace) EXCEPT A8's `noteTitle` was again pointing at
  A5's Text output instead of «Provided Input» — same mis-pick as before;
  "recurring trap" note added under the table. Remaining: fix A8, then build
  A11–A16.
- **2026-07-02 (evening, cont.)** — User found the Select Variable view: blue
  tokens render beneath their source action; A7's output token is labeled
  **"Ask for Input"** on Sequoia (Apple's guide says "Provided Input" — label
  follows the action name). A8 re-pointed correctly by the user. Spec relabeled.
- **2026-07-02 (night)** — A11–A12 Replaces built and chained ✓. A13 Create Note
  added: **has a Name field** (open question answered), folder is
  `ReminderNotes` (no space — spec updated to match). To finish A13: Contents =
  «Updated Text» from the LAST Replace; Name = «noteTitle» `[`«token»`]`;
  Open When Run ON. Then FIRST TEST RUN — check title, body, unreplaced
  `{{…}}` placeholders, and whether template line 1 duplicates the title.
- **2026-07-02 — FIRST SUCCESSFUL TEST RUN.** Note created: title
  `test note RN_20260702145437` (user used space, no brackets — fine), all
  placeholders replaced (chaining verified), dates correct. One issue as
  predicted: template's title line duplicated as body line 1 → repo template
  updated to drop the title line (body now starts at `Created:`; `{{TITLE}}`
  placeholder retired, A10 Replace now a no-op — optional to delete).
  **User must re-copy the updated template to iCloud Drive → Shortcuts.**
  Remaining: A14 (relay URL Text), A15 (Copy to Clipboard), A16 (Notification),
  then build Shortcut B.
- **2026-07-02 — Shortcut B built through B7** (screenshot-verified). Sequoia
  differences folded into spec: a **Receive header action** exists ("Receive
  Text and Apps input from Nowhere; If there's no input: Continue" — Continue
  is required for the manual branch); Find Notes renders as "Find All Note
  where" with Sort by + Limit checkbox/Get 1. Fix needed: uncheck **Allow
  Multiple Lines** on B2's Ask for. Remaining: B8–B12 (If-no-result alert /
  Open Note), then end-to-end round-trip test.
- **2026-07-02 — Shortcut B COMPLETE** (screenshot-verified, all 12 steps +
  Receive header). Multiline unchecked ✓. B8's If input auto-coerced to the
  note's «Name» — accepted as equivalent. Next: confirm A14–A16 built, then
  round-trip test (Mac), then iOS test after iCloud sync.
- **2026-07-02 — ALL TESTS PASSED on macOS.** Failure path (bogus token →
  alert), success path (token → note opens), full round trip (paste relay URL
  into reminder URL field → click chip → correct note opens). No permission
  prompts appeared. System is live on the Mac.
- **2026-07-02 — iOS VERIFIED.** The reminder's URL chip opens the correct
  note on iPhone. Cross-platform goal achieved; project complete. Optional
  cleanups remain: delete the no-op `{{TITLE}}` Replace (A10) and turn OFF
  "Open When Run" in A13 once confidence is established.

---

## Sources — prefer these (Apple, authoritative)

Favor Apple's official docs over forums/Reddit for UI mechanics. Apple documents
*concepts* well but is often thin on per-action UI; for those, verify on-screen.

- [Use variables in Shortcuts on Mac](https://support.apple.com/guide/shortcuts-mac/use-variables-apdd02c2780c/mac) — Ctrl-click → Insert Variable; Set Variable stores the previous action's output
- [Intro to variables in Shortcuts on Mac](https://support.apple.com/guide/shortcuts-mac/intro-to-variables-apdb5506f698/mac)
- [Variable types used in Shortcuts on Mac](https://support.apple.com/guide/shortcuts-mac/variable-types-apdd2b316022/mac)
- [Shortcuts User Guide (Mac)](https://support.apple.com/guide/shortcuts-mac/welcome/mac)
- [What's new in Shortcuts](https://support.apple.com/en-us/101583) — current Notes actions list
