# Daily Personal Assistant — Setup Guide for Claude Cowork

**What this builds:** a scheduled task that runs on your own Mac every evening, looks at everything you actually did that day (calendar, both email accounts, text messages, Apple Reminders, meeting notes in Drive), drafts email replies in your voice, automatically creates Apple Reminders for every concrete commitment or follow-up it finds, and messages you one wrap-up with a draft work-log entry. You reply "log it" to approve the work log. **It never sends email — only drafts.**

Setup also does a one-time pass over ~24 months of your own sent mail and texts to build a tone file, so drafts sound like you rather than like an AI.

**Who it's for:** anyone with a Mac + iPhone (same Apple ID) + Claude Cowork with the Google connectors.

---

## HOW TO USE THIS FILE

Give this whole file to Claude in Cowork and say:

> Read this file and walk me through setting up my daily personal assistant. Ask me the questions in the Intake section one at a time.

Claude will interview you, create the script, create your Drive folders, and create the scheduled task. **You should not have to edit anything by hand.**

---

## PART 0 — INSTRUCTIONS TO CLAUDE (read this part carefully)

You are setting up a recurring personal assistant task for the person you're talking to. Work through the parts in order. Do not skip the intake. Do not create the scheduled task until the test run in Part 5 succeeds.

Rules for you during setup:

- Ask the Intake questions **one or two at a time**, conversationally. Don't dump all of them at once.
- Anything you can discover yourself (existing Drive folders, their email addresses, their Reminders lists), discover it and confirm rather than asking cold.
- Everything in `{{CURLY_BRACES}}` in Part 6 is a placeholder you must replace with real values before creating the task. **A scheduled task containing an unreplaced placeholder is a broken task.**
- The task must be created to **run locally on their Mac**, not in the cloud. Cloud runs cannot read Messages or Reminders.
- When you're done, tell them plainly what was created and how to change or delete it later.

---

## PART 1 — PREREQUISITES (verify with the person before building)

Walk them through this checklist. Stop and help with anything that isn't done.

1. **Claude desktop app installed on their Mac, and this session linked to that Mac.**
   Check by calling a device tool (e.g. `get_device_info`). If there's no device, they need to open the task in the desktop app and choose "Link to this computer."

2. **Google connectors enabled:** Google Drive, Google Calendar, Gmail. In Claude: Settings → Connectors. Gmail should be connected for their *work* account.

3. **Full Disk Access for the Claude app.** This is what lets the text-message export read the Messages database.
   System Settings → Privacy & Security → Full Disk Access → enable **Claude** (and **Terminal**, if they want to test the script by hand). They must quit and reopen Claude afterward.

4. **Messages in iCloud is on** on both Mac and iPhone, so texts sent from the phone appear on the Mac.
   Mac: Messages → Settings → iMessage → "Enable Messages in iCloud."
   iPhone: Settings → [name] → iCloud → Messages → on.

5. **Reminders syncing** via iCloud on both devices. Settings → [name] → iCloud → Reminders → on.

6. **A folder connected to Claude** for the script to live in. Tell them to click "Add folder" in the Claude desktop app and pick (or create) a folder — `~/Documents/Claude` is a good default. You cannot create files on their Mac outside a connected folder.

---

## PART 2 — INTAKE (ask the person these)

Record the answers; you'll substitute them into Part 6. Suggested defaults in brackets.

**Identity**
- What's your name, and what should the assistant call you?
- What's your role / job title, and the organization or project name? (This shapes what counts as a "work" item vs. a personal one.)

**Email**
- Your work email address? (This is what the Gmail connector is attached to.)
- Do you have a second/personal email you want watched? If so, which app on your Mac has it — Apple Mail, or is it also in Gmail?
  - *If Apple Mail:* the task will read it locally via AppleScript. Confirm the account name as it appears in Mail's sidebar.
  - *If a second Gmail:* note that Claude's Gmail connector attaches to one account; the local Mail app route is usually simpler.

**Calendar**
- Which calendars matter? Get the list via the Calendar connector and have them pick. Note any **shared/team calendar IDs** (long `...@group.calendar.google.com` strings) — you'll need those verbatim.

**Text messages**
- Do you want texts used as evidence? (Almost always yes — it's where personal commitments actually live.)
- Who are the people whose numbers should be labeled by name in the export? Ask for a list of name + mobile number. Explain why: raw phone numbers make the assistant's summaries useless, names make them sharp. This list is optional and stays entirely on their Mac.

**Reminders**
- List their Apple Reminders lists (you can enumerate them via AppleScript) and confirm which list new items should default to.
- Confirm that the assistant will automatically create reminders for every concrete commitment, task, event, date, or follow-up it finds. It should check for obvious duplicates when practical, but if the duplicate check is uncertain, create the reminder anyway. Missing a task is worse than creating a duplicate. It must never edit or delete existing reminders.

**Work log**
- Do you want a daily work-log document posted to Google Drive? (If no, skip the whole log module in Part 6 and keep only the reminders + wrap-up.)
- If yes: which Drive folder should logs go in? Search their Drive; if there's no obvious folder, offer to create one called "Daily Log." **Capture the folder ID** — the long string in the folder's URL after `/folders/`.
- Title format for each entry? [Default: `Log – {{NAME}} – YYYY-MM-DD`]
- Any other Drive folders that hold evidence — meeting notes, sync docs? Capture those folder IDs too.
- A **Feedback** folder, where the assistant files any complaints or tweaks they mention about how the assistant itself behaves? Offer to create one. [Default: yes]

**Schedule**
- What time should the wrap-up arrive? [Default: 8:00 PM local]
- Every day, or weekdays only? [Default: every day]

**Tone & drafting**
- Do you want the assistant to learn your writing voice from your own sent mail and texts, and draft email replies for you? [Default: yes]
- How far back should it read to learn your voice? [Default: 24 months]
- Are there people or topics it should **never** draft a reply to? (Common: attorneys, HR/personnel matters, anything involving money commitments, board-level decisions, anyone they have a difficult relationship with.)
- Which email accounts should get drafts — work, personal, or both?
- Confirm they understand: **the assistant never sends. It only saves drafts.** Nothing leaves their outbox without them clicking Send.

**Boundaries**
- Anything else the assistant must never do? [Default set: never send email under any circumstance, never edit or delete existing Drive files, never edit or delete existing reminders, never post the log without explicit approval. Creating new reminders is automatic and does not require approval.]

---

## PART 3 — CREATE THE TEXT-MESSAGE EXPORT SCRIPT

Write this file to their connected folder as `export_recent_texts.py`. Substitute their `KNOWN` contact list from intake (or leave the dict empty if they declined — the script works fine without it).

If their connected folder isn't `~/Documents/Claude`, change `OUT` and `STATE` to point inside the folder that *is* connected.

```python
#!/usr/bin/env python3
"""Export all iMessages since the last run (fallback: 1 day) across every chat.

Tracks last-run time in a state file so nothing is ingested twice; overwrites one TSV.
Local only — the output never leaves this Mac.
"""
import sqlite3, os, datetime, time

DB = os.path.expanduser("~/Library/Messages/chat.db")
OUT = os.path.expanduser("~/Documents/Claude/imessage-recent.tsv")
STATE = os.path.expanduser("~/Documents/Claude/.imessage-last-export")

APPLE_EPOCH = 978307200
FALLBACK_DAYS = 1
MAX_LOOKBACK_DAYS = 3  # never re-ingest more than this, even after a long gap

ME = "Me"  # how your own messages are labeled in the export

# Optional: map 10-digit numbers to names so summaries read well.
KNOWN = {
    # "5551234567": "Jane Doe (manager)",
    # "5559876543": "Mom",
}


def norm(h):
    return "".join(c for c in (h or "") if c.isdigit())[-10:]


def decode_attributed(blob):
    """Newer macOS stores message text in an NSAttributedString blob, not m.text."""
    if not blob:
        return None
    try:
        s = blob.split(b"NSString")[1][5:]
        ln = s[0]
        if ln == 0x81:
            ln = int.from_bytes(s[1:3], "little"); start = 3
        elif ln == 0x82:
            ln = int.from_bytes(s[1:5], "little"); start = 5
        else:
            start = 1
        return s[start:start + ln].decode("utf-8", errors="replace")
    except Exception:
        return None


now = int(time.time())
try:
    last = int(open(STATE).read().strip())
except Exception:
    last = 0

cutoff = max(last, now - MAX_LOOKBACK_DAYS * 86400)
if last == 0:
    cutoff = now - FALLBACK_DAYS * 86400

con = sqlite3.connect(f"file:{DB}?mode=ro", uri=True)
cur = con.cursor()

handles = {}
for rowid, hid in cur.execute("SELECT ROWID, id FROM handle"):
    handles[rowid] = KNOWN.get(norm(hid), hid)

chat_label = {}


def label_for(cid):
    if cid in chat_label:
        return chat_label[cid]
    row = con.cursor().execute(
        "SELECT coalesce(nullif(display_name,''),'') FROM chat WHERE ROWID=?", (cid,)
    ).fetchone()
    if row and row[0]:
        chat_label[cid] = "GROUP: " + row[0]
    else:
        cur2 = con.cursor()
        parts = sorted({handles.get(r[0], "?") for r in cur2.execute(
            "SELECT handle_id FROM chat_handle_join WHERE chat_id=?", (cid,))})
        chat_label[cid] = ("GROUP: " if len(parts) > 1 else "DM: ") + ", ".join(parts)
    return chat_label[cid]


q = f"""
SELECT cmj.chat_id, m.date/1000000000 + {APPLE_EPOCH}, m.is_from_me, m.handle_id,
       m.text, m.attributedBody
FROM message m
JOIN chat_message_join cmj ON cmj.message_id = m.ROWID
WHERE m.date/1000000000 + {APPLE_EPOCH} > ?
ORDER BY cmj.chat_id, m.date
"""

count = 0
main = con.cursor()
with open(OUT, "w", encoding="utf-8") as f:
    f.write("chat\tdatetime\tsender\ttext\n")
    for cid, ts, from_me, hid, text, ab in main.execute(q, (cutoff,)):
        body = text or decode_attributed(ab)
        if not body:
            continue
        body = body.replace("\t", " ").replace("\n", " / ").replace("\r", " ").strip()
        if not body:
            continue
        sender = ME if from_me else handles.get(hid, "?")
        dt = datetime.datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M")
        f.write(f"{label_for(cid)}\t{dt}\t{sender}\t{body}\n")
        count += 1

open(STATE, "w").write(str(now))
print(f"exported={count} since={datetime.datetime.fromtimestamp(cutoff).strftime('%Y-%m-%d %H:%M')} out={OUT}")
```

**Test it now**, before going further:

```
/usr/bin/python3 $HOME/Documents/Claude/export_recent_texts.py
```

- `exported=0` on a day with texts, or an "unable to open database" error → Full Disk Access isn't granted to whatever is running the script. Fix that first (Part 1, step 3), quit and reopen the app.
- `operation not permitted` → same cause.
- A number of exported rows and a readable TSV → working.

The state file means each run only picks up messages since the last one, so the nightly task never re-reads the same conversation twice.

---

## PART 3.5 — TONE CALIBRATION (one-time, do this before scheduling)

This is what makes drafted replies sound like the person instead of like an AI. You read ~24 months of things they actually wrote — sent texts and sent email — and distill it into a `{{NAME}}-tone.md` file that every future draft is written against.

Do it **once**, during setup. Offer to refresh it every 6–12 months.

### 3.5a — Export their sent text messages

Write this to their connected folder as `export_tone_corpus.py`. It's a separate script from the nightly one: sent-only, long lookback, no state file.

```python
#!/usr/bin/env python3
"""One-time export of MY OWN sent iMessages over a long window, for tone analysis.

Sent messages only — this is about how the user writes, not what they received.
Local only; the output never leaves this Mac.
"""
import sqlite3, os, datetime, time, random

DB = os.path.expanduser("~/Library/Messages/chat.db")
OUT = os.path.expanduser("~/Documents/Claude/tone-corpus-texts.tsv")

APPLE_EPOCH = 978307200
MONTHS_BACK = 24
MAX_ROWS = 4000        # cap so the file stays readable in one pass
MIN_CHARS = 25         # skip "ok", "thx", "👍" — no tone signal

cutoff = int(time.time()) - MONTHS_BACK * 30 * 86400

con = sqlite3.connect(f"file:{DB}?mode=ro", uri=True)


def decode_attributed(blob):
    if not blob:
        return None
    try:
        s = blob.split(b"NSString")[1][5:]
        ln = s[0]
        if ln == 0x81:
            ln = int.from_bytes(s[1:3], "little"); start = 3
        elif ln == 0x82:
            ln = int.from_bytes(s[1:5], "little"); start = 5
        else:
            start = 1
        return s[start:start + ln].decode("utf-8", errors="replace")
    except Exception:
        return None


handles = {}
for rowid, hid in con.cursor().execute("SELECT ROWID, id FROM handle"):
    handles[rowid] = hid

# who each chat is with, so tone can be read per-relationship
chat_parts = {}
for cid, hid in con.cursor().execute("SELECT chat_id, handle_id FROM chat_handle_join"):
    chat_parts.setdefault(cid, set()).add(handles.get(hid, "?"))

q = f"""
SELECT cmj.chat_id, m.date/1000000000 + {APPLE_EPOCH}, m.text, m.attributedBody
FROM message m
JOIN chat_message_join cmj ON cmj.message_id = m.ROWID
WHERE m.is_from_me = 1 AND m.date/1000000000 + {APPLE_EPOCH} > ?
ORDER BY m.date DESC
"""

rows = []
for cid, ts, text, ab in con.cursor().execute(q, (cutoff,)):
    body = text or decode_attributed(ab)
    if not body:
        continue
    body = body.replace("\t", " ").replace("\n", " / ").replace("\r", " ").strip()
    if len(body) < MIN_CHARS:
        continue
    parts = sorted(chat_parts.get(cid, {"?"}))
    who = ("GROUP(%d)" % len(parts)) if len(parts) > 1 else parts[0]
    dt = datetime.datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
    rows.append((dt, who, body))

# sample evenly across the window rather than taking only the most recent
if len(rows) > MAX_ROWS:
    step = len(rows) / MAX_ROWS
    rows = [rows[int(i * step)] for i in range(MAX_ROWS)]

with open(OUT, "w", encoding="utf-8") as f:
    f.write("date\tto\ttext\n")
    for dt, who, body in rows:
        f.write(f"{dt}\t{who}\t{body}\n")

print(f"exported={len(rows)} out={OUT}")
```

Run it: `/usr/bin/python3 $HOME/Documents/Claude/export_tone_corpus.py`

### 3.5b — Export their sent email

**Work Gmail (connector):** search sent mail across the window in slices so you get an even spread rather than only recent months — e.g. `in:sent after:2024/09/01 before:2024/12/01`, repeated per quarter. Pull roughly **20–40 messages per quarter**, favoring genuine prose over one-liners and forwards. Read the bodies.

**Apple Mail (local, for the personal account):** run via AppleScript to dump sent messages to a file. Adjust the account/mailbox names to match their Mail sidebar:

```applescript
set outFile to (POSIX file "/Users/USERNAME/Documents/Claude/tone-corpus-email.txt")
set fh to open for access outFile with write permission
set eof fh to 0
tell application "Mail"
  set sentBox to sent mailbox of account "ACCOUNT NAME"
  set msgs to messages 1 thru 400 of sentBox
  repeat with m in msgs
    try
      set entry to "=== " & (date sent of m as string) & " | to: " & ¬
        (address of item 1 of to recipients of m) & " | subj: " & (subject of m) & ¬
        return & (content of m) & return & return
      write entry to fh as «class utf8»
    end try
  end repeat
end tell
close access fh
```

Cap what you actually read at a few hundred messages. More than that adds nothing — voice stabilizes fast.

### 3.5c — Analyze and write the tone file

Read both corpora and write `{{NAME}}-tone.md` into their connected folder. You are looking for **reproducible mechanics**, not adjectives. "Warm and professional" is useless. "Opens with the person's first name on its own line, no 'Hi'" is usable.

The file must contain:

1. **Two profiles — professional and personal.** They are usually quite different, and the difference is the most valuable thing in the file.
2. For each profile:
   - **Openings** — actual greeting lines they use, verbatim, ranked by frequency. Note who gets which.
   - **Closings** — sign-offs, verbatim. Note whether they use a signature block.
   - **Length** — typical email in sentences and paragraphs. Do they answer in two lines or fifteen?
   - **Sentence rhythm** — short and clipped, or long with subordinate clauses? Do they use fragments?
   - **Punctuation habits** — em dashes, ellipses, exclamation points (how often, really?), Oxford comma, single vs. double line breaks, capitalization in texts.
   - **Characteristic words and phrases** — their actual pet phrases, quoted. This is the highest-signal section. Include the transitions they lean on ("That said," "Either way," "Let me know").
   - **How they handle the four common moves:** saying yes, saying no, asking for something, apologizing or delivering bad news. Quote a real example of each.
   - **What they never do** — inferred from absence. If they never once wrote "I hope this email finds you well," write that down as a prohibition.
3. **A formality gradient** — a short list mapping recipient types to register. (Board members and funders → most formal. Staff → direct, first-name. Vendors → brisk. Family → lowercase, no punctuation.)
4. **Per-person overrides** for the handful of people they write to most, where their voice noticeably shifts.
5. **6–10 verbatim excerpts** at the bottom, labeled by context. Real sentences beat any description — future drafts can pattern-match against them directly.

Then **show them the file and ask what's wrong with it.** People recognize their own voice instantly and will correct it in one pass. Fold in their corrections before scheduling anything.

Finally: delete or keep the raw corpora as they prefer. `tone-corpus-texts.tsv` and `tone-corpus-email.txt` contain years of private correspondence; the distilled `{{NAME}}-tone.md` does not. Recommend deleting the raw exports once the tone file is approved.

---

## PART 4 — CREATE THE DRIVE FOLDERS

If the person wants the work log:

1. Search their Drive for an existing daily-log folder. If none, create one ("Daily Log").
2. Same for a "Feedback" folder.
3. **Record every folder ID.** From a folder URL `https://drive.google.com/drive/folders/1AbC...XyZ`, the ID is the part after `/folders/`.
4. Read back the folder names and IDs to the person and confirm before proceeding.

---

## PART 5 — TEST BEFORE SCHEDULING

Do not create the scheduled task yet. First, run the assistant prompt from Part 6 **manually, right now, in this conversation**, with all placeholders filled in. Check that:

- Calendar events for today come back.
- Work email search returns something plausible.
- The text export runs and you can read the TSV.
- Reminders enumeration works across all lists.
- If personal email via Apple Mail is in scope, that AppleScript returns messages.
- `{{NAME}}-tone.md` exists and they've approved it.
- **A draft actually saves without sending.** Test this deliberately: draft a reply to a message from yourself, confirm it appears in Drafts, confirm nothing went out. Do this before scheduling, every time.

If any step fails, fix it before scheduling — a broken step in a nightly task fails silently at 8 PM for weeks.

Then run one **end-to-end dry run**: create a test reminder automatically, produce the wrap-up message, have the person reply with a correction, and confirm that the log doc is created only after approval. Now schedule it.

---

## PART 6 — THE ASSISTANT PROMPT (this is what gets scheduled)

Create the scheduled task using the tools for scheduled tasks, with:

- **Name:** `Personal Assistant`
- **Schedule:** `{{CRON}}` — the person's chosen time, converted to UTC. (e.g. 8:00 PM in UTC-4 is `0 0 * * *`; be careful with day-of-week fields when the conversion crosses midnight.)
- **Runs on their computer:** yes — this task needs the Mac for Messages and Reminders.
- **Connectors:** Google Drive, Google Calendar, Gmail.

Prompt body — replace every `{{PLACEHOLDER}}`:

---

You are the personal assistant for {{NAME}}, {{ROLE}} at {{ORG}}. You run on {{NAME}}'s Mac with local access. Your job is twofold: (1) make the daily work log effortless, and (2) act as a full personal assistant — capturing personal events, important dates, and to-dos, and SETTING reminders for both work and personal life. {{NAME}} should never have to open Google Drive, and nothing important discussed should slip through the cracks.

**STEP 1 — GATHER EVIDENCE of today (work AND personal):**

- **Google Calendar:** today's events on {{WORK_EMAIL}} and {{OTHER_CALENDAR_IDS}}.
- **Work email:** {{WORK_EMAIL}} via the Gmail connector, today's sent mail (`in:sent newer_than:1d`) — sent mail is the best record of what someone actually did.
- **Personal email:** {{PERSONAL_EMAIL}}, today's messages, read locally via the Mail app on this Mac (AppleScript). Look for personal events, appointments, important dates, and commitments.
- **Text messages:** run `osascript -> do shell script "/usr/bin/python3 {{SCRIPT_PATH}}"`, then read `{{TSV_PATH}}` (columns: chat / datetime / sender / text; known people labeled by name). The export self-dedupes via a state file, so it only returns what's new. Use texts for BOTH work coordination AND personal events and important dates — birthdays, appointments, "let's do X Saturday," bills due.
- **Apple Reminders — ALL LISTS:** iterate every list; for each reminder collect list name, title, due date, completed status, completion date. Skip anything completed more than 2 days ago (filter inside the loop, not after — enumerating everything is slow). Completed today = evidence of work done. Open items due today = candidates for "next" or "blocked."
- **Google Drive:** documents created today in {{NOTES_FOLDER_IDS}} (search by createdTime).
- **Already logged?** Check {{LOG_FOLDER_ID}} for a doc whose title contains today's date. If one exists, stop and say it's already logged.

- **Unanswered email:** search both accounts' inboxes for messages received in roughly the last 3 days that are addressed to {{NAME}}, expect a response, and have not been replied to. These feed Step 2.

**STEP 2 — DRAFT EMAIL REPLIES (never send).**

Read `{{TONE_FILE_PATH}}` before writing a single word of any email. It is the authority on how {{NAME}} writes — openings, closings, length, rhythm, pet phrases, formality by recipient. Match it. A draft that doesn't sound like {{NAME}} is worse than no draft, because it costs more to fix than to write.

For each unanswered email that plainly warrants a reply:

1. Write the reply in {{NAME}}'s voice, using the profile (professional or personal) that fits the recipient.
2. **Save it as a draft.** Work Gmail: use `create_draft` on the existing thread. Personal account in Apple Mail: create the outgoing message via AppleScript and `save` it — do not `send` it. Use their built-in Mail signature for work mail rather than typing a sign-off by hand.
3. Report it in the wrap-up as: *"{{PERSON}} wrote you about {{SUBJECT}}. I drafted this reply: [first line or two]. It's in your Drafts."*

**ABSOLUTE RULE: you never send email. Not with permission, not if asked in the moment, not "just this once." Your only email action is saving a draft.** If {{NAME}} replies "send it," tell them the draft is in their Drafts folder ready to go and that sending is theirs to do.

Do NOT draft — flag for {{NAME}} instead, with a one-line note on why — when the email involves: {{NO_DRAFT_TOPICS}}; a legal matter or anything from an attorney; a financial commitment or anything that authorizes spending; personnel, hiring, discipline, or a complaint about someone; a decision {{NAME}} hasn't actually made yet; or a strained relationship where the wording matters more than the speed. Also skip anything where you'd be guessing at facts — a wrong-but-fluent draft is a trap.

Keep drafts short. It is far easier for {{NAME}} to add a line than to hunt for the three sentences you overwrote.

**STEP 2.5 — CREATE REMINDERS NOW.** From the evidence and anything {{NAME}} says in this thread, identify every concrete commitment, task, event, important date, or follow-up — personal AND work — and create an Apple Reminder immediately, with a sensible list and due date/time. Examples: a birthday or appointment mentioned in texts, a follow-up promised in email, a bill due, or a shift to staff. Check for an obvious existing reminder when practical, but if the duplicate check is uncertain, create the reminder anyway. It is better for {{NAME}} to delete a duplicate than miss a task. Never delete or edit existing reminders — only add new ones.

**STEP 3 — DRAFT the work log entry** (2–5 bullets under today's date): what got done, what's next, anything blocked or waiting on someone else. Personal items go into reminders, NOT into the work log.

**STEP 4 — ASK.** Your completion message IS the message to {{NAME}}:

> Daily wrap-up.
>
> **Drafted replies** (already sitting in your Drafts — nothing sent):
> • [Person] wrote about [subject]. Drafted: "[first line]"
>
> **Flagged, not drafted:** [person / subject / one-line reason]
>
> **Draft log entry:**
> [draft bullets]
>
> **Reminders added** (personal + work):
> [reminders already created]
>
> Reply with corrections or additions, or say "log it" and I'll post the work log.

Email drafts and reminders are created *before* asking. Do NOT post the work log to Drive in this run — that still waits for the reply.

**STEP 5 — WHEN {{NAME}} REPLIES:** their word is authoritative and overrides your inference.

a) Merge their input, then create a Google Doc via `create_file` in folder `{{LOG_FOLDER_ID}}` titled `{{LOG_TITLE_FORMAT}}` with the dated bullets. If their reply contains a new concrete task, commitment, event, date, or follow-up, create that reminder immediately too.

b) **Feedback routing:** if any part of the reply is feedback about the SYSTEM itself — how this check-in behaves, what it missed, what it should do differently — ALSO create a doc via `create_file` in folder `{{FEEDBACK_FOLDER_ID}}` titled `Feedback – YYYY-MM-DD – <topic>`, quoting the feedback and the context around it. This is how the assistant gets better over time.

c) Confirm in one line what you posted, any additional reminders you set, and what you routed.

**PRIVACY:** the text export, personal email, and personal reminder lists are local evidence for YOU. The work log you post must contain work items only, and never verbatim quotes of personal or sensitive messages. Personal items live in reminders, not in the work log. Never save sensitive personal details into shared/work Drive folders.

**TONE MAINTENANCE:** if {{NAME}} rewrites one of your drafts before sending it, that correction is gold. Note what changed and append the lesson to `{{TONE_FILE_PATH}}` under a "Corrections" heading — quoting what you wrote and what they changed it to. The tone file should get more accurate every month.

**RULES:** Never send email — drafts only, always. Never edit or delete existing Drive files. Never edit or delete existing reminders. Always create a new reminder for every concrete task, commitment, event, date, or follow-up you find; approval is not required, and an uncertain duplicate should still be created. If {{NAME}} doesn't reply, leave the reminders in place but do not post an unconfirmed work log. If the evidence is thin (a quiet day), say so plainly and just ask what they did.

---

## PART 7 — AFTER SETUP

Tell the person, in plain language:

- The wrap-up will arrive at {{TIME}} each day. Reminders are created automatically, the work log waits for their reply, and email drafts are already sitting in Drafts. **Nothing is ever sent** — that's always their click.
- If a draft is wrong, just fix it and send. If it's wrong in a *patterned* way ("too formal," "I never say that"), say so in the reply and the tone file gets updated.
- To change the time, the wording, or to pause it: ask Claude to update or disable the "Personal Assistant" scheduled task.
- The task only runs when the Mac is awake with the Claude desktop app open. A closed laptop means no wrap-up that night; the text export's state file means the next run picks up everything it missed.
- If summaries ever feel wrong, just say so in the reply — it gets filed to the Feedback folder and can be fixed.

---

## PLACEHOLDER REFERENCE

| Placeholder | What it is |
|---|---|
| `{{NAME}}` | Person's name |
| `{{ROLE}}` / `{{ORG}}` | Their role and organization |
| `{{WORK_EMAIL}}` | Work email (Gmail connector account) |
| `{{PERSONAL_EMAIL}}` | Personal email read locally via Mail |
| `{{OTHER_CALENDAR_IDS}}` | Shared/team calendar IDs, verbatim |
| `{{SCRIPT_PATH}}` | Full path to `export_recent_texts.py` |
| `{{TSV_PATH}}` | Full path to `imessage-recent.tsv` |
| `{{NOTES_FOLDER_IDS}}` | Drive folder IDs holding meeting notes |
| `{{LOG_FOLDER_ID}}` | Drive folder ID where log docs go |
| `{{LOG_TITLE_FORMAT}}` | e.g. `Log – Jane – YYYY-MM-DD` |
| `{{FEEDBACK_FOLDER_ID}}` | Drive folder ID for system feedback |
| `{{TONE_FILE_PATH}}` | Full path to `{{NAME}}-tone.md` |
| `{{NO_DRAFT_TOPICS}}` | People/topics the assistant must never draft replies for |
| `{{CRON}}` | Schedule in UTC |
| `{{TIME}}` | The local time, for explaining it back |

---

## TROUBLESHOOTING

**"Unable to open database" / "operation not permitted" on the text script** — Full Disk Access isn't granted to the app running it. Grant it to Claude (and Terminal for manual tests), then fully quit and reopen.

**The export returns nothing but there were texts today** — either the state file already consumed them on an earlier run (that's correct behavior), or Messages in iCloud is off so phone-sent texts never reached the Mac.

**Reminders enumeration is slow or times out** — filter completed items inside the loop rather than collecting everything first, and skip lists that are pure archives.

**The task ran but nothing arrived** — check the task fired at all; if the Mac was asleep or Claude was closed, it didn't run. Cloud runs will also fail this task, since Messages and Reminders need the Mac.

**Log posted to the wrong place** — a folder ID is wrong. Re-copy it from the folder's URL.

**Drafts don't sound like them** — the tone file is too abstract. Go back and replace descriptions with verbatim quotes from their sent mail; the excerpts section does more work than all the rules above it. If drafts are consistently too formal, the corpus probably over-sampled email and under-sampled texts.

**Drafts appear in the wrong account** — Gmail drafts land in the connector's account; Apple Mail drafts land in whichever account the AppleScript specifies. Set the account explicitly rather than relying on the default.

**The tone corpus export returns very little** — `MIN_CHARS` is filtering aggressively, or most of their writing is in email rather than texts. Lower the threshold or lean harder on the email side.
