aboutsummaryrefslogtreecommitdiff
path: root/.ai/workflows/daily-prep.org
blob: 6589355041429fda34e745968fc07225c9b5449a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
#+TITLE: Daily Prep Workflow
#+AUTHOR: Craig Jennings & Claude
#+DATE: 2026-02-23

* Overview

This workflow prepares Craig for the next workday by reviewing scheduled meetings, identifying priorities, and blocking time on the calendar. It ensures Craig walks into every meeting prepared and has a plan for the day's focused work.

This is typically run the evening before or morning of the workday in question.

* Problem We're Solving

Without daily prep, Craig risks:
- Walking into meetings without the right context loaded
- Missing opportunities to drive key decisions or raise important points
- Losing track of action items owed to or from specific people
- Not having focused work time protected on the calendar
- Reactive instead of proactive days

*Impact:* Unprepared meetings waste everyone's time. Unplanned days let urgent displace important.

* Exit Criteria

- All meetings for the day are reviewed with prep notes
- 1:1 meetings have talking points drawn from todo.org and session history
- Day's priorities are identified and confirmed by Craig
- Time blocks are placed on the calendar for focused work
- Any quick tasks (< 5 min) are done during prep itself
- Craig feels ready for the day

* When to Use This Workflow

- When Craig says "let's prep for tomorrow" or "daily prep" or similar
- During evening wrap-up if there are meetings the next day
- Morning of a workday before meetings start
- When Craig asks for the standup brief alone ("what's my standup report", "let's do the daily standup report", "give me the standup brief") — see Standup-only mode below

* Modes

The workflow runs in one of two modes based on the trigger phrase. Pick the mode at workflow start. Don't switch mid-run.

** Full-prep mode (default)

Trigger: "let's prep for tomorrow", "daily prep", or any general prep-cycle phrase.

Runs Phase A → Phases 1-5 → Phase 6 (only if a standup is on the calendar) → Phase 7 → Phase 8 → Phase 9.

** Standup-only mode

Trigger: "what's my standup report", "let's do the daily standup report", "give me the standup brief", or similar standup-specific phrasing.

Runs *only* a slim Phase A + Phase 6 + a conditional Phase 8 + Phase 9. Skip Phases 1-5 and Phase 7 entirely.

*** Slim Phase A (standup-only)

Fetch only what Phase 6 needs:

1. =todo.org= — for WAITING items (blockers) and DONE-since-cutoff (completed work).
2. Previous prep doc — anchor for the lookback (check =inbox/= then =daily-prep/=, take most recent).
3. Most recent =.ai/sessions/= summary — for the "what did I do" question.

Skip the calendar fetches, the Proton grep, and the [#A]/[#B] todo pull. Phase 6 Step 1's sweep handles the rest.

*** Where the brief lands

- If a prep doc for today already exists at =inbox/YYYY-MM-DD-daily-prep.org=, append or replace its =* Standup Brief= section.
- If no prep doc for today exists, create =inbox/YYYY-MM-DD-daily-prep.org= with only the =* Standup Brief= section populated. Full prep can be added later by re-running in full-prep mode.

*** Phase 8 in standup-only mode

Only run if a stale prep doc exists in =inbox/= that's older than yesterday. Otherwise skip — there's nothing to archive.

Use standup-only mode when Craig wants the brief fast (e.g., right before standup) without rebuilding the day's plan.

* Prep Doc Structure

The prep doc has a fixed set of top-level sections. Don't invent new ones. If substantive content surfaces that doesn't fit one of these headings, mention it in chat after the workflow finishes rather than adding it to the prep doc.

Canonical sections (full-prep mode produces all; standup-only produces just =* Standup Briefs=):

| Section                          | Phase that writes it | Purpose                                                                    |
|----------------------------------+----------------------+----------------------------------------------------------------------------|
| =* Heads-up=                     | Phase 7              | Substantial situational context that changes Craig's frame for the day     |
| =* Day's Priorities=             | Phase 3              | Actionable items for today (thin links to =:quick:reactive:= todo.org tasks) |
| =* Meetings / Work Blocks=       | Phase 4              | Chronological schedule for the day (meetings + work blocks interleaved)    |
| =* Standup Briefs=               | Phase 6              | Yesterday / Today / Blockers content for the standup meeting               |
| =* Upcoming Deadlines=           | Phase 7              | Next 4-6 weeks of relevant deadlines, briefly                              |
| =* [Next day]'s Anchor Tasks=    | Phase 7              | Explicit forward commitments for tomorrow. Phase 2 of next-day's prep reads this |

Order in the prep doc follows the table top-to-bottom: Heads-up first (frame-setter), Day's Priorities next (action surface), then schedule, then standup, then deadlines, then forward-commitment.

** Day's Priorities entries are thin links to todo.org tasks (2026-05-12 rule)

Each actionable entry under =* Day's Priorities= is a *pointer to a todo.org task*, not a copy of its content. Form:

#+begin_example
** TODO [#X] <task title> — [[file:../todo.org::*<task title>][todo.org]]
<one line on why it's today's priority — deadline, blocker, what just landed>
#+end_example

All the substance — descriptions, drafted messages, research findings, sub-tasks, =VERIFY= asks, recommended-approach blocks — lives in the matching =todo.org= task, created or updated by Phase 3. If a todo.org task doesn't exist yet, create one (with the conventional priority cookie / Linear ID in the heading) and link to it. This keeps everything in one place (todo.org), so the prep doc never accretes content that then has to be transferred back.

Exceptions that stay in the prep doc as content (not links):
- *Completed-today entries* — once a task is done, its heading becomes a dated log entry (=** YYYY-MM-DD Day @ HH:MM ...=, see [[file:../../.claude/...][feedback_done_tasks_become_dated_log_headings]] — i.e. the dated-heading rule) and stays in the prep doc as the day's record. If the work also has a durable todo.org home, the dated entry links to it.
- The =* Standup Briefs=, =* Heads-up=, =* Upcoming Deadlines=, and =* [Next day]'s Anchor Tasks= sections — those are prep-doc-native and don't map to todo.org tasks.

(Craig's instruction, 2026-05-12, extended 2026-05-15. Sub-steps 3b–3f below implement the convention: each Action item becomes its own =** TODO= in =todo.org= with =:quick:= + =:reactive:= tags, and the prep doc references it via a thin link under =* Day's Priorities= when it belongs in today's plan. No grouped =** Email Response= / =** Slack Response= / =** Linear Response= / =** PR Review= sub-sections in the prep doc — the source mix lives in the tags on each todo.org task.)

** Triage Action items become =:quick:reactive:= todo.org tasks (2026-05-15 rule)

Every Action item surfaced by Phase 3 sub-steps 3b–3f (email, Slack, Linear, PRs) becomes its own top-level =** TODO= in =todo.org= with =:quick:= + =:reactive:= tags. The prep doc's =* Day's Priorities= section links to those tasks as thin links per the rule above — no grouped Response sub-sections.

Form:

#+begin_example
** TODO [#B] Read [[https://linear.app/deepsat/issue/SE-378][SE-378 Kostya Testing Results]] :quick:reactive:kostya:
** TODO [#B] Re-review Vrezh's PR #167 after fixes :quick:reactive:vrezh:
** TODO [#B] Reply to Subbu re: RTX action items :quick:reactive:subbu:
#+end_example

Rules:

- Plain-prose heading, lead with the verb (Read / Re-review / Reply / Address / Schedule / Review).
- Default priority =[#B]=. Bump to =[#A]= only if the item blocks a teammate or a deadline lands inside 7 days.
- Always =:quick:= + =:reactive:=. Add person/entity tags (=:vrezh:=, =:kostya:=, =:subbu:=, =:rtx:=, etc.) when the dependency is sharp.
- Link the source in the heading when it has a URL — Linear issue, GitHub PR, Gmail thread, Slack permalink — using =[[url][label]]= form. The recommended approach and response content (when relevant) goes in the task body, not the heading.
- Placement in =todo.org=: end of =* Work Open Work= (before =* Work Incubate=) unless a =* Triage= / =* Inbox= section exists near the top.

If the item belongs in today's plan, also add a thin link under =* Day's Priorities= in the prep doc:

#+begin_example
** TODO [#B] <task title> — [[file:../todo.org::*<task title>][todo.org]]
<one line on why it's today's priority — deadline, blocker, what just landed>
#+end_example

Items that don't belong in today's plan stay in =todo.org= and surface on a future day's prep via Phase 3 sub-step 3a's =:reactive:= pull.

* Approach: How We Work Together

** Continuous flow (no mid-phase gates)

Phases A through 7 run continuously. Don't stop between phases for Craig's input or confirmation. Information surfaced in later phases (especially Phase 3 email/Slack/Linear scans) frequently reframes what Craig wants from earlier phases — meeting goals, carry-forward decisions, priority order, time blocking. Stopping at Phase 1 to ask "what do you want from this meeting?" means asking Craig to react with stale context, before scans surface the email that might change his answer.

Build all phases through Phase 7, then present the assembled draft and surface every question and proposed adjustment at the final review.

Exception: stop only if a scan turns up something that *blocks* further building. Examples: a meeting was canceled and the whole day's structure changes; a security or compliance issue Craig must adjudicate before email triage proceeds. Otherwise keep going.

This rule applies to all phases including Phase 1's "collaborative review" line and Phase 2's planned-vs-actual review. Both are framed as collaborative in their phase descriptions; the collaboration happens once, at the end, against the assembled prep doc.

** Phase A: Data Gathering (one parallel batch)

Before any synthesis or interaction, pull every source the prep doc needs in a *single batch of parallel tool calls*. These reads are all independent — issue them in one message, not as a sequential round-trip per source:

1. =mcp__google-calendar__list-events= for the *personal* account, scoped to the day being prepped.
2. =mcp__google-calendar__list-events= for the *work* account, same scope.
3. Grep =~/.emacs.d/data/pcal.org= for items on that day. This is the Proton Calendar export (=pcal= = personal calendar). The same directory has =gcal.org= and =dcal.org= for Google personal + DeepSat, but those are already covered by the MCP queries in steps 1 and 2 — only =pcal.org= adds non-redundant items.
4. Read =todo.org= — collect [#A] and [#B] tasks plus anything with DEADLINE: or SCHEDULED: touching the day.
5. List + read the *previous* prep doc. Check =inbox/= first (active prep docs not yet archived), then =daily-prep/= (the archive). Take the most recent file by date — usually yesterday's, but may be older if Craig was off (PTO, weekend, missed days). The lookback for the standup brief is anchored on this file's date, so accuracy matters.
6. Read the most recent =.ai/sessions/= summary file (for the standup brief's "What did I do since last standup?" question).

Phases 1-5 below all work from this in-memory snapshot. *Do NOT re-query the calendars in Phase 4* — the time-blocking pass uses the same data Phase A fetched. A typical daily-prep used to run 4-5 sequential round-trips just for data gathering; this collapses to one.

** Phase 1: Meeting Review

Working from the Phase A calendar snapshot, present each meeting with:

1. *Time and duration*
2. *Meeting name*
3. *Owner* (who scheduled/owns the meeting)
4. *Official agenda* (from calendar description)
5. *What Craig needs from this meeting* -- decisions to drive, points to make, information to convey, people to persuade

For the last item, Claude may not know Craig's goals for the meeting. Present what's known and Craig will clarify during review.

*** 1:1 Meeting Prep

1:1 meetings get deeper preparation:

1. Check todo.org for tasks tagged with or related to the person
2. Review session histories since the last 1:1 with that person for relevant events, decisions, and context
   - Default lookback: since the last 1:1 with that person
   - Craig may ask to go further back for long-running items
3. Identify:
   - Status updates Craig should share (progress on things they care about)
   - Questions Craig needs to ask
   - Decisions that need their input
   - Action items owed to or from them

Capture the meeting list with what's known about each (time, owner, official agenda, who's accepted vs declined, what Craig might need). Don't stop here for Craig's input. Bring questions about meeting goals to the final review at the end of Phase 7, when the cross-source picture from Phase 3 is in hand. The collaborative review of the meeting list happens once, against the assembled prep doc, not as a mid-flow gate.

** Phase 2: Planned vs. Actual Review

Before setting tomorrow's priorities, review what was planned for today against what actually happened. This catches work that slipped and prevents it from silently disappearing.

1. Pull the current day's prep doc (if one exists). If it has a populated =* [Today]'s Anchor Tasks= section (written by yesterday's Phase 7 as the explicit handoff), use that as the canonical carry-forward list. Otherwise fall back to inferring carry-forward by listing the day's planned work blocks.
2. For each block, note: completed, partially done, or not started
3. For items that didn't happen, identify why (took longer than expected, blocked, deprioritized, meetings ran over)
4. Carry forward anything that still matters into the priority list for the next day, with updated time estimates based on what we learned today
5. Add all carried-forward items as =TODO= entries in the new prep doc's Day's Priorities section — don't just note them in the Planned vs Actual table. Unfinished tasks from yesterday become today's tasks automatically unless Craig cuts them.

This step keeps the daily prep honest. If a 1-hour task consistently takes 3 hours, the estimates need to change. If work keeps getting bumped by meetings, that's a pattern worth raising.

** Phase 3: Day's Priorities

Assemble priorities automatically from multiple sources. No interactive confirmation. Craig reviews the prep doc as a whole when it's done.

For each Action item: create or update a =:quick:reactive:= task in =todo.org= per the *Triage Action items become =:quick:reactive:= todo.org tasks* rule above. Then, if the item belongs in today's plan, add a thin-link entry under the prep doc's =* Day's Priorities= section. Order Day's Priorities by urgency — most time-sensitive or blocking first. If Craig wants to add or remove a priority, he edits the prep doc directly.

Sources contributing to Day's Priorities: todo.org, email, Slack, Linear, PRs.

*Linear digest / notification emails don't get their own task.* If sub-step 3b returns a Linear digest email saying "you have N unread notifications," that's not an Action item — Linear notifications surface either via 3e (the direct Linear query) or via the underlying per-notification emails Linear sends. Classify the digest as Noise-keep (or Noise-trash if the per-notification emails are also flowing through) and don't add a separate "Linear notifications check" todo.org task.

*** Recommended Approach Pattern (used by sub-steps 3b, 3d, 3e)

When an item involves a non-trivial decision or judgment that benefits from analysis, include a =recommended approach= subheader before the response draft. The approach is the executor's analysis — situation, options, recommendation with rationale, considerations Craig should weigh — so Craig can evaluate the recommendation itself, not just the wording.

Skip the approach subheader for routine acknowledgments, simple status replies, or "yep, looks good" approvals.

Source-specific examples of when to *include* the approach subheader:

- *Email:* decisions like grant applications, partnership replies, public-facing or sensitive responses
- *Slack:* @mentions with explicit asks, items where someone is blocked waiting on Craig
- *Linear:* @mentions requesting input, Blocked tickets Craig owns, Needs-Review items where the call isn't trivially obvious

Format (consistent across all three sources):

#+begin_example
***** YYYY-MM-DD Day @ HH:MM:SS -ZZZZ recommended approach
<situation, options, recommendation with rationale, considerations>
***** YYYY-MM-DD Day @ HH:MM:SS -ZZZZ recommended response
<draft response text, OR proposed action like a state change>
#+end_example

Generate timestamps with =date "+%Y-%m-%d %a @ %H:%M:%S %z"= so they're accurate, not estimated.

*** Sub-step 3a: From todo.org

1. Pull all [#A] tasks from todo.org.
2. Add time-sensitive items (DEADLINE: or SCHEDULED: touching the day).
3. Carry forward unfinished items surfaced by Phase 2 — but skip any item already added by step 1 or 2 above. A task that was [#A] yesterday and didn't finish gets carried forward by Phase 2 and would also re-appear in step 1's [#A] pull. Dedupe by org-mode heading text or =:ID:= property if present.
4. Pull open =:reactive:= tasks (created by prior preps under the *Triage Action items become =:quick:reactive:= todo.org tasks* convention) — these are pending quick-fire responses that should stay visible until processed. Dedupe against steps 1-3. Surface them as thin links in Day's Priorities; Craig drops the ones that don't fit today's plan.

Priorities typically include:
- Messages to send (Slack, email)
- Meetings to schedule
- Documents to send out for review
- Follow-ups to make
- Prep work needed before a meeting

*** Sub-step 3b: From email

Scan email since the prior prep doc's *mtime* (when the file was last written, not the date in its filename or title) — both accounts, unread or unanswered, with the =summarize-emails=-style noise filter (=NOT flag:list=, addressed-to-Craig). Express the cutoff to Gmail as =after:YYYY/MM/DD HH:MM:SS= so messages dated *between the prior prep's write time and now* land in scope. Anchoring on filename date or Gmail's day-granular =after:= operator drifts when a prep doc is generated late at night for the next day — the wrong window catches a full extra calendar day or misses several hours.

*Track every message path returned by the scan* (Action, FYI, and Noise alike). Sub-step 3c uses this list to mark-read only the emails actually processed, avoiding a race condition with emails arriving mid-workflow.

For each email, classify:

- *Action* — explicit ask, deadline, request for decision, or Craig is the bottleneck
- *FYI* — informational, no action required (note in session-context.org if substantive, otherwise drop)
- *Noise-keep* — automated/CC-only with no expected response, but has residual value (mark read; keep in inbox archive)
- *Noise-trash* — automated/CC-only with no expected response AND no residual value (trash it; see criterion below)

*Trash criterion.* Trash if both are true:

1. No transactional / financial / security record value (would I ever search for this in 6 months?)
2. Not direct human-to-human correspondence

Otherwise mark-read but keep.

*Per-account bias.* DeepSat work account biases toward keeping — defense engineering audit-trail value, storage is free. Personal Gmail biases toward trashing — high volume, low residual value, search clutter.

Common *Noise-trash* patterns:
- Newsletter / blog digest content (Substack subscriptions you don't actually read, daily/weekly roundups)
- Retail / SaaS / EDC marketing promos
- Social-network engagement bait (LinkedIn social digests, Instagram followers, Bandcamp DMs)
- Aggregate notification digests redundant with their source app (Linear digest emails, Notion/Miro daily/weekly engagement pings)
- Wrong-recipient mail (mailing-list typo addressed to a different person)
- Past-event calendar artifacts (cancellations/updates for events that already happened)
- Stock-tip teasers, deal alerts, review-request prompts (Hotels.com / Airbnb "rate your stay")

Common *Noise-keep* patterns:
- Financial: dividend statements, monthly statements, payment confirmations, invoices (paid or unpaid)
- Account security: new-login alerts, new payment method added, password reset, OAuth grants
- Domain / registrar admin (renewal notices, WHOIS contact reminders)
- Direct human correspondence (even if FYI, even if you didn't reply)
- Booking confirmations for trips actually being taken
- PR / code review notifications (audit-trail value on the work account)
- CI / deploy failure alerts (incident archive)

*Email link format.* Every email surfaced in the prep doc must link directly to the actual message in the right Gmail account, not just to a generic Gmail tab. Construct the URL as:

#+begin_example
https://mail.google.com/mail/u/<account-index>/#all/<thread-id>
#+end_example

Two pieces matter:

- *Account index.* The =u/<n>= segment selects which Gmail account opens the link. Indexes are stable per Craig's setup:
  - =u/0= → personal account (=craigmartinjennings@gmail.com=, served by the =google-docs= MCP)
  - =u/1= → DeepSat work account (=craig.jennings@deepsat.com=, served by the =google-docs-work= MCP)
  Pick the index that matches the source MCP. A work email linked with =u/0= opens personal Gmail and shows nothing - that's the failure mode this rule prevents.
- *Thread ID.* Use the =threadId= field from =listMessages= or =getMessage=, not the =messageId=. Gmail's web URL routes by thread. Use the =#all/= view (works whether the message is still in the inbox or has been archived) - don't use =#inbox/=, since the link breaks the moment the message moves out of inbox.

If a project routes mail through a different account layout (other tenants, additional accounts), record the index mapping in that project's =.ai/notes.org= and override the defaults above.

For each Action item:

1. *Star the email in Gmail* so it's flagged in Craig's inbox outside the prep doc:
   #+begin_src bash
   python3 .ai/scripts/maildir-flag-manager.py star --reindex /path/to/message.eml
   #+end_src
2. *Read* the email content (use =eml-view-and-extract-attachments.py= in stdout mode if needed).
3. *Capture substantive content* in the right place based on what kind of information it is:
   - =deepsat/knowledge.org= (or the project's equivalent) — persistent facts the project should remember: new contacts to add to the roster, system or infrastructure details, strategic decisions, transcription corrections, vendor relationships.
   - =.ai/session-context.org= — today's session context: what was read, decisions made or pending, follow-ups identified for later in the session.
   When in doubt, default to session-context. The next session can promote anything worth keeping into knowledge.org during wrap-up.
4. *People-Context Check (runs before the recommended response is drafted).* When the Action item involves a specific person (sender, recipient, or a named third party referenced in the body), look that person up in =deepsat/knowledge.org= (Key People table, plus the Team Details section if present). Pull role and reporting line, relationships to other key people (family, prior employer, advisor vs. employee), tone and working-style signals, and recent context that affects how Craig should phrase the response. If the person isn't in =knowledge.org=, capture what's known there before writing the draft — the people layer is persistent context, every future prep gets faster when this layer is complete. Skip the check for purely transactional senders (Mercury, GitHub notifications, Linear bots). The recommended-approach + recommended-response then incorporates the people-context: tone, channel choice (email vs Slack vs in-person), and framing should reflect the relationship.
5. *Create the =:quick:reactive:= todo.org task* per the *Triage Action items become =:quick:reactive:= todo.org tasks* rule above. The heading carries the verb (Reply / Read / Approve / Decline / Schedule), the source link as =[[mail-link][From X: Subject]]= form, and tags =:quick:reactive:[person]:=. The recommended-approach + recommended-response content (per the Recommended Approach Pattern) goes in the task body, not the heading.
6. *If the item belongs in today's plan, link from Day's Priorities* using the thin-link form:
   #+begin_example
   ** TODO [#B] Reply to <Person> re: <subject> — [[file:../todo.org::*Reply to <Person>][todo.org]]
   <one line on why today — deadline, blocker, who's waiting>
   #+end_example
   Items that don't belong in today's plan stay in =todo.org= and surface on a future day's prep via sub-step 3a's =:reactive:= pull.

For each FYI item: read it, capture substantive content into knowledge.org or session-context per the routing above, then drop it from further processing. Don't add to the prep doc or =todo.org=.

For each Noise-keep item: no per-message action beyond the read-state pass at sub-step 3c. Don't add to the prep doc.

For each Noise-trash item: trash it. Trashing removes the message from INBOX and parks it in Trash for 30 days before Gmail's auto-purge, so no separate mark-read is needed at sub-step 3c.

#+begin_src bash
# MCP path (preferred — works directly against Gmail):
mcp__google-docs__trashMessage --messageId <id>             # personal account
mcp__google-docs-work__trashMessage --messageId <id>        # DeepSat account

# maildir path (fallback for offline / mu4e workflow):
python3 .ai/scripts/maildir-flag-manager.py trash --reindex /path/to/message.eml
#+end_src

The =:quick:reactive:= todo.org task is the durable home; the Day's Priorities thin link surfaces it for the day. Don't paste the email body, recommended approach, or response draft into the prep doc — those live in the todo.org task.

*** Sub-step 3c: Mark processed email as read

After 3b is fully complete, mark *only the message paths 3b processed* (Action, FYI, Noise-keep) as read — not all unread INBOX emails. Noise-trash items are already handled at 3b and don't need a read-state pass.

#+begin_src bash
# MCP path (preferred):
mcp__google-docs__modifyMessageLabels --messageId <id> --removeLabelIds '["UNREAD"]'

# maildir path (fallback):
python3 .ai/scripts/maildir-flag-manager.py mark-read --reindex /path/to/msg1 /path/to/msg2 ...
#+end_src

Scoped mark-read avoids a race where an email arriving between 3b's scan and 3c's mark-read would be silently marked read without being processed.

Stars persist (separate flag), so Action items remain findable in Gmail by their star, not by unread state.

*Before exiting Phase 3, verify the triage actions actually executed:* every Action item has a Gmail star AND is marked read; every FYI and Noise-keep item is marked read; every Noise-trash item is in Trash. The Phase 3 audit footer at sub-step 3g is the forcing function for source coverage; this verification is the parallel for triage execution. Producing only the audit footer without running the API calls leaves Craig with an unread inbox even though every message was *seen* in the prep doc — defeats the inbox-zero purpose of the workflow. Count what was processed (e.g., "44 trashed, 5 noise-keep marked-read, 19 starred + marked-read, 30 FYI marked-read") and confirm the totals match the classification.

*** Sub-step 3d: From Slack

Query Slack since the prior prep doc's *mtime* (when the file was last written, not its filename date). Three streams (filters out general channel chatter Craig wasn't directly addressed in):

1. *DMs Craig hasn't replied to.* Call =mcp__slack-deepsat__conversations_unreads= with =channel_types='dm'= and =max_channels=100=. Each row is a DM message Craig hasn't read.
2. *Channel @mentions of Craig.* Call =mcp__slack-deepsat__conversations_unreads= with =mentions_only=true= and =max_channels=100=. This is the *only reliable* way to find @mentions in this MCP — see the search-doesn't-work-for-mentions note below. Limitation: this only catches *unread* @mentions; ones Craig already saw are out of scope, which is the right trade-off (already-read mentions were seen and either actioned or consciously skipped).
3. *Thread replies in threads Craig started or last commented in.* No direct API for "threads I started." Practical approach: in the unreads pulled by streams 1 and 2, look at the =ThreadTs= column — non-empty values mean the message is a thread reply. Use =mcp__slack-deepsat__conversations_history= on the parent channel to fetch the full thread context if any reply looks substantive.

*Slack search caveat (don't waste time here).* =mcp__slack-deepsat__conversations_search_messages= does *not* index =<@USERID>= tokens as searchable text. Searches for =<@U0A8AJTEM9V>=, =@craig.jennings=, or even Craig's plain display name return empty even when @mentions exist. Slack's own search has the same limitation — the "Mentions & Reactions" panel in the Slack app uses the unreads-with-mentions API, not search. Don't fall back to =conversations_search_messages= to find @mentions; use =conversations_unreads(mentions_only=true)= as above. The search tool is fine for keyword searches in message text (e.g. "find any message mentioning 'STRATFI'").

For each result, classify:

- *Action* — explicit ask, decision needed, or Craig is the bottleneck
- *FYI* — informational, no action required (capture in knowledge.org or session-context if substantive, otherwise drop)
- *Noise* — bot pings, automated alerts, off-topic mentions (drop silently)

For each Action item:

1. *Read* the message and surrounding thread context.
2. *Capture substantive content* in =deepsat/knowledge.org= (or the project's equivalent) for persistent project facts, or =.ai/session-context.org= for today's context. Same routing rules as Sub-step 3b — default to session-context when unsure.
3. *People-Context Check* — same as sub-step 3b's step 4. When the message involves a specific person, look them up in =knowledge.org= before drafting. Skip for transactional bot pings.
4. *Create the =:quick:reactive:= todo.org task* per the *Triage Action items become =:quick:reactive:= todo.org tasks* rule above. The heading carries the verb (Reply / React / Address / Schedule), the source link as =[[slack-permalink][From X in #channel: brief description]]= form, and tags =:quick:reactive:[person]:=. The recommended-approach + recommended-response content goes in the task body.
5. *If the item belongs in today's plan, link from Day's Priorities* using the thin-link form:
   #+begin_example
   ** TODO [#B] Reply to <Person> re: <topic> — [[file:../todo.org::*Reply to <Person>][todo.org]]
   <one line on why today — who's blocked, what just landed>
   #+end_example
   Items that don't belong in today's plan stay in =todo.org= and surface on a future day's prep via sub-step 3a's =:reactive:= pull.

For each FYI item: read it, capture substantive content per the routing above, then drop. No prep-doc entry or todo.org task.

After processing all items, mark *only the specific DMs and @mentions we touched* as read in Slack — not channel-wide. The Slack MCP should expose a per-message mark-read capability; if the available MCP doesn't support it, skip this step and let Craig manage Slack read state himself. Do NOT mark channel chatter as read; only the items the query returned.

The =:quick:reactive:= todo.org task is the durable home; the Day's Priorities thin link surfaces it for the day. Don't paste the message text, recommended approach, or response draft into the prep doc — those live in the todo.org task.

*** Sub-step 3e: From Linear

Query Linear since the prior prep doc's *mtime* (when the file was last written, not its filename date), using =updatedAt= as the timestamp anchor. Three streams:

1. Tickets *assigned to Craig* with state changes or new activity.
2. Tickets *created by Craig* with state changes or new comments (someone else moved or replied).
3. Tickets where Craig is *@mentioned* in a recent comment.

Use Linear MCP =list_issues= with the appropriate filters; =get_issue= and =list_comments= for individual reads.

For each result, classify:

- *Action* — ticket in "Needs Review" assigned to Craig; @mention requesting input; new comment with a question; deadline within ~48h; ticket assigned to Craig in a "blocked-on-me" state
- *FYI* — state change on Craig's ticket by someone else; comment that's a status update; related-ticket activity worth knowing
- *Noise* — bot updates, automated transitions (drop silently)

For each Action item:

1. *Read the ticket* — description, recent comments, state history.
2. *Capture substantive content* in =deepsat/knowledge.org= (people roles, system facts, strategic decisions) or =.ai/session-context.org= (today's review notes). Same routing rules as Sub-step 3b — default to session-context when unsure.
3. *People-Context Check* — same as sub-step 3b's step 4. When the ticket involves a specific person (assignee, reviewer, commenter, @mentioned), look them up in =knowledge.org= before drafting. Skip for bot updates and automated transitions.
4. *Create the =:quick:reactive:= todo.org task* per the *Triage Action items become =:quick:reactive:= todo.org tasks* rule above. The heading carries the verb (Review / Comment / Resolve / Address), the source link as =[[https://linear.app/...][SE-NNN ticket title]]= form, and tags =:quick:reactive:[person]:=. The recommended approach + recommended response (draft comment, proposed state change, combined action like "comment + reassign to Vrezh" — "what Craig should do," not just reply text) goes in the task body.

   *When the action item is a comment or @mention,* paste the comment text into the task body so Craig can draft a reply against it. Fetch via =mcp__linear__list_comments=:
   #+begin_example
   ** TODO [#B] Reply to <Author> on [[https://linear.app/...][SE-NNN]] :quick:reactive:[author]:
   Why action needed: direct @mention; ties to <related ticket if any>.

   *** <Author> — <YYYY-MM-DD HH:MM> — comment on SE-NNN
   #+begin_quote
   <the comment text, verbatim>
   #+end_quote
   *** Craig's reply (fill in / approve, then I post it to the ticket)
   <placeholder>
   #+end_example
   Same idea for an FYI comment Craig should see — paste it, don't just reference it. (Feedback memory: =feedback_linear_comment_as_child_header=.)
5. *If the item belongs in today's plan, link from Day's Priorities* using the thin-link form:
   #+begin_example
   ** TODO [#B] Review SE-NNN <ticket title> — [[file:../todo.org::*Review SE-NNN][todo.org]]
   <one line on why today — Needs Review, blocker, deadline>
   #+end_example
   Items that don't belong in today's plan stay in =todo.org= and surface on a future day's prep via sub-step 3a's =:reactive:= pull.

For each FYI item: read it, capture substantive content per the routing above, then drop. No prep-doc entry or todo.org task.

*Two deliberate divergences from email/Slack:*

1. *No mark-as-read step.* Linear has no "unread" concept. The processed signal is implicit — once Craig acts on the ticket (comments, changes state), it stops appearing in the next query. Items he doesn't act on re-surface tomorrow, which is correct.
2. *No "star" or "save" equivalent.* Linear ticket URLs in the prep doc are enough.

*Volume note:* if a query returns >20 tickets, surface the count and prioritize Action signals first (Needs Review assigned to Craig, @mentions, blocked tickets, deadlines).

The =:quick:reactive:= todo.org task is the durable home; the Day's Priorities thin link surfaces it for the day. Don't paste the ticket description, recommended approach, or response draft into the prep doc — those live in the todo.org task.

*** Sub-step 3f: From Open PRs

Scan open pull requests on the project's primary repo (per-project; for DeepSat the canonical repo is `~/projects/work/deepsat/code/orchestration_dashboard_mvp`). Use `gh pr list` to enumerate, classify each, and surface Action items in the prep doc.

Scan command (single round-trip):

#+begin_src bash
gh pr list --repo <owner>/<repo> --state open --json number,title,author,reviewRequests,isDraft,updatedAt,headRefName,additions,deletions,url
#+end_src

For each result, classify:

- *Action* — Craig is in `reviewRequests`, OR Craig was a reviewer and the author force-pushed since Craig's last review (re-review needed), OR the PR is blocked on Craig's response in a thread.
- *FYI* — open PRs Craig isn't reviewing but worth noting (a teammate's branch in flight, draft PRs, Craig's own PRs awaiting others).
- *Noise* — bot PRs (dependabot, renovate, etc.). Drop silently.

For each Action item:

1. *Read the PR* — diff summary, recent commits, review state, any unresolved threads.
2. *People-Context Check* — same as sub-step 3b's step 4 for the PR author and the requesting reviewer.
3. *Create the =:quick:reactive:= todo.org task* per the *Triage Action items become =:quick:reactive:= todo.org tasks* rule above. The heading carries the verb (Review / Re-review / Unblock), the source link as =[[PR-URL][PR #N title (author)]]= form, and tags =:quick:reactive:[author]:=. The recommended-approach + recommended-response content goes in the task body.
4. *If the item belongs in today's plan, link from Day's Priorities* using the thin-link form:

#+begin_example
** TODO [#B] Review PR #N <title> — [[file:../todo.org::*Review PR #N][todo.org]]
<one line on why today — review requested, blocking author, re-review after force-push>
#+end_example

Items that don't belong in today's plan stay in =todo.org= and surface on a future day's prep via sub-step 3a's =:reactive:= pull.

For FYI items (Craig's own PRs awaiting review, draft PRs in flight): don't create a todo.org task. Surface them in =* Heads-up= (Phase 7) as a one-line note ("Craig's open PRs awaiting review: #145, #167") so the queue stays visible without inflating the action surface.

*Two deliberate divergences from email/Slack:*

1. *No mark-as-read step.* PR review state is implicit — once Craig submits a review or a comment, the PR's review-status changes and re-classification happens on the next prep.
2. *No "star" equivalent.* PR URLs in the prep doc are enough; Craig's review queue is already filterable in the GitHub UI.

*Per-project repo configuration.* The repo path is project-specific. For projects without a primary repo (personal documentation projects, etc.), skip this sub-step and mark `prs ✗ (no primary repo)` in the audit footer. For projects with multiple repos in active development, scan each in turn; surface Action items with the repo name prefixed in the title.

The =:quick:reactive:= todo.org task is the durable home; the Day's Priorities thin link surfaces it for the day. Don't paste the PR description, recommended approach, or response draft into the prep doc — those live in the todo.org task.

*** Sub-step 3g: Cross-source dedup and urgency re-sort

After 3a-3f have written all their =:quick:reactive:= todo.org tasks and Day's Priorities thin links, do a final cleanup pass.

*Cross-source dedup.* Scan the =:reactive:= tasks created this prep cycle for items that reference the same conversation or topic. Common cases:

- Vrezh DMs Craig about a Linear ticket *and* comments on the ticket itself — both surface as separate =:reactive:= tasks
- An email points at "let's discuss on the ticket" — the ticket also has activity
- A Slack thread is the followup to an email exchange

For each candidate duplicate pair, surface to Craig:

#+begin_quote
These two reactive tasks look like the same conversation: [task with Email link] and [task with Linear link]. Should I collapse them into one, or keep both?
#+end_quote

Wait for Craig's call. If he says collapse, keep the source he picks, paste the other source link into the task body as "see also: [other-link]", and drop the other task. Drop the matching Day's Priorities thin link too. Don't auto-collapse.

*Urgency re-sort.* Re-order all entries under =* Day's Priorities= by urgency:

1. Items with deadlines today or already overdue
2. Items where Craig is blocking someone (Slack blocked-on-Craig, Linear Blocked tickets, Needs-Review assigned to Craig)
3. Items with deadlines within ~48 hours
4. Other [#A] tasks
5. Time-sensitive but lower-stakes items
6. Everything else

Day's Priorities entries are all thin links to todo.org tasks now (no grouped source sub-sections), so re-ordering is a flat sort — just move the heading lines into urgency order. Craig can re-order further when he reviews the prep doc; this just gives him a sane starting order.

*** Sub-step 3h: Phase 3 audit footer (forcing function)

After 3a-3g are done, write a single comment line at the top of the prep doc — directly below the =#+DATE:= header — recording which sources actually got checked:

#+begin_example
# Sources checked: todo.org ✓ | email-personal ✓ | email-deepsat ✓ | Slack ✓ | Linear ✓ | prs ✓
#+end_example

Replace the ✓ with ✗ for any source that was skipped, and add a parenthetical reason after each ✗ (e.g. =Slack ✗ (MCP disconnected)= or =email-personal ✗ (auth scope error)=). If a source was scanned but returned no items, keep the ✓ — empty is a valid scan result; "didn't run at all" is what this line catches.

This footer is the canary that surfaces silent skips. The reason it's a forcing function: writing the line means deciding what mark each source gets, which means actually checking that each source ran. A skipped sub-step now requires an explicit ✗, not a silent omission of a section.

** Phase 4: Time Blocking

Once priorities are confirmed, block time on the calendar to accomplish them. Phase 4 also writes the prep doc's =* Meetings / Work Blocks= section — a single chronological list interleaving meetings with focused-work blocks, top to bottom in time order.

*** Quick Tasks (< 5 minutes)
Tasks like "schedule a meeting with Ryan" or "send a Slack message" should be done during the prep workflow itself, not scheduled separately. Draft the message or create the calendar event on the spot.

*** Focused Work Tasks
For anything requiring more than a few minutes:

1. Ask Craig for a time estimate on each item
2. Use the Phase A calendar snapshot — *do not re-query the calendars*. The same events are already in context.
3. *Compute the day's active window.* Default 10:00 to 17:00, every day of the week (weekends included). If the prep is being run *same-day* (the prep doc's date matches today's date) and the workflow start-time is later than 10:00, the window starts at the start-time instead. Existing calendar appointments, known personal commitments (guests arriving, travel, off-time blocks Craig flagged), and the last-30-min next-day-prep reservation remove time from the window. Whatever's left is fillable with priorities. Don't auto-treat Saturday or Sunday as "off." Fill the window with tasks. If Craig wants personal time on a weekend, he marks it on the calendar or flags it during prep.
4. List the schedule with open slots clearly marked. Show the active window's start, end, and remaining fillable minutes after subtracting appointments.
5. Propose when each task fits, considering:
   - Meeting proximity (prep work should be near the meeting it supports)
   - Energy/focus (harder tasks earlier if possible)
   - A half hour around lunchtime to eat when possible (protein shake or leftovers is fine -- this can be compressed or skipped on heavy days)
   - Always reserve the last 30 minutes of the workday for daily prep for the following day. This is non-negotiable -- it's what keeps the cycle going.
6. Craig confirms or adjusts the proposed schedule

*** Placing Calendar Blocks
- Place time blocks on Craig's personal Google calendar (=Craig Google=)
- Can also place blocks on DeepSat calendar directly using MCP server with =account_id: "work"=
- Use the calendar event workflows (add-calendar-event.org) for creating events

** Phase 5: Prep Work

With the schedule set, work on anything that needs to be ready for the day's meetings. Examples:

- Watch tutorial videos and take notes
- Draft or polish documents for review
- Prepare talking points or materials
- Research topics that will come up in meetings
- Draft messages that are part of the day's priorities

This phase is where the bulk of the session time goes. Work through items in priority order, with meeting-related prep taking precedence based on meeting time.

** Phase 6: Standup Brief

Generate the standup brief late in the workflow so the rest of the day's analysis is already done. The brief draws from Phase 2 (Planned vs Actual), Phase 3 (Day's Priorities), and the activity sweep below. Phase 6 writes the prep doc's =* Standup Briefs= section.

Skip this phase entirely on days with no standup on the calendar.

*** Step 1: Sweep recent activity for off-Claude signals

Before drafting, check these sources for activity since the previous prep doc's date (the lookback anchor from Phase A step 5):

1. *Sent email* — both accounts. Outgoing threads from Craig: decisions communicated, replies to action items, follow-ups, intros made.
2. *Slack* — Craig's recent messages across channels and DMs. Decisions, status updates, threads where Craig participated.
3. *todo.org* — items marked DONE since the cutoff. New TODOs added that hint at fresh context (new commitments, new blockers).
4. *Linear* — tickets Craig moved to a new state, commented on, or created. Use the Linear MCP to query.

These surface team-visible work that lives outside session history (work done in mu4e, Slack, the Linear UI, or off-Claude conversations).

*** Step 2: Draft the brief

Combine session history + the Step 1 sweep + Phase 3 priorities + todo.org WAITING items into the three-question structure below.

*Meeting selection.* Recurring meetings are excluded from both the Yesterday and Today sections — they're not news to the team. For non-recurring meetings:

- *Yesterday section:* include only meetings Craig actually attended. Filter on Craig's own response status from the calendar event:
  - =accepted= → include
  - =tentative= or =declined= → exclude (don't assume attendance)
- *Today section:* include all non-recurring meetings regardless of response status. Craig still needs to communicate what he plans to attend or decide between.

The Google Calendar MCP returns =responseStatus= per attendee — filter on Craig's own response, not the event's overall status. Recurring events expose =recurringEventId= or =recurrence=; treat the presence of either as the recurring marker.

*Content rules.*

- *Stay first-person.* Report what Craig did, said, or decided. Don't volunteer others for work or report what others said they would do — that's their standup, not Craig's. If a teammate's commitment is relevant context, frame it as something Craig is waiting on, not as a status update on their behalf.
- *Match deadline precision to what's actually known.* If a deadline is "early next week," don't tighten it to "Monday." If the commitment is "before the proposal goes out," don't sharpen it to "Friday EOD." Vague is honest when vague is the truth.

1. *What did I do since last standup?* Anchor the lookback at the previous prep doc's date (Phase A step 5). Pull session history, session-context.org, completed tasks, and the Step 1 sweep results from that date forward. Since DeepSat standup is a workday-recurring meeting, the previous prep doc's date is the previous standup date even if intervening days were weekends or PTO. Use explicit day references ("Monday" not "yesterday") since the prep doc may be written the evening before.
2. *What am I doing today?* Pull from the day's priorities (Phase 3 output). Keep it to 2-3 items max.
3. *Blockers: mine or yours?* The bar is "did this actually stop me from making progress?", not "is someone else involved?" A WAITING item in todo.org is only a blocker if Craig already tried to move forward and got stopped. Mere dependencies don't qualify unless they've already impaired progress. Default to under-reporting — draft without borderline items and let Craig add them back in Step 3. FYI items (decisions or context worth flagging that aren't blockers) come after blockers and stay loose.

The brief should be concise enough to read aloud in under 60 seconds. Include enough context that Craig doesn't have to think on his feet, but not so much that it turns into a status report.

*** Step 3: Present the draft and ask what's missing

Show Craig the full draft brief — Yesterday, Today, Blockers/FYI sections all populated. Then ask:

#+begin_quote
Anything I missed? Common categories: off-Claude meetings or phone calls, paperwork or forms submitted, intros made or received, vendor conversations, anything else not captured in session/email/Slack/Linear.
#+end_quote

Recognition is faster than recall. Craig can react to "did you make any intros?" much faster than to "what did you do?" The categories are prompts, not a checklist.

*** Step 4: Refine and finalize

Apply Craig's additions and any wording adjustments. The brief is now ready for standup.

*** Step 5: Offer to capture learnings

After Step 4, scan Craig's refinements for non-obvious patterns:

- Did he cut a category of item the workflow said to include?
- Did he add a category the workflow didn't tell you to look for?
- Did he change wording in a way that suggests a phrasing rule (e.g., "say 'continued focus on X' instead of 'worked on X'")?

If a refinement looks like a generalizable rule, offer it back to Craig:

#+begin_quote
I noticed you [removed all 1:1 meetings from Yesterday / added the off-Claude phone call with Ryan / changed "completed proposal draft" to "continued focus on proposal"]. Want me to add this to the workflow? Proposed rule: "[concrete rule text]"
#+end_quote

Wait for explicit confirmation before editing the workflow. Never edit on your own judgment.

If Craig confirms, append the rule to the *Updates and Learnings* section at the bottom of this file with today's date and a one-line description. If the new rule supersedes existing text inside Phase 6, also update the inline text and note "(updated YYYY-MM-DD — see Updates and Learnings)" in the affected section so the audit trail is complete.

If the refinement looks like a one-off, don't propose a rule. Default to under-proposing — false-positive rules clutter the workflow. The bar is "would I want this guidance the next time I draft a brief?" If yes, propose. If no, drop it.

** Phase 7: Final Section Writeups

Three sections remain after Phase 6: =* Heads-up=, =* Upcoming Deadlines=, and the next day's =* [Day]'s Anchor Tasks=. Phase 7 writes them, drawing on what earlier phases already surfaced.

Order doesn't matter between the three sub-steps. They write to distinct sections and don't depend on each other.

*** Sub-step 7a: Heads-up

Write a top-level =* Heads-up= section near the top of the prep doc (above =* Day's Priorities=).

Heads-up is the executive summary of what would change Craig's frame for the day. Terse, situational, day-shaping. Pull from sources earlier phases surfaced:

- *Substantial FYIs* from Phase 3 sub-steps 3b/3d/3e — items like "Eric quietly progressed two partnership threads on Apr 24" or "Vrezh force-pushed all three branches overnight" that affect what Craig should expect today
- *Schedule changes* from Phase 1 — "Arusyak 15:00-16:00 is being rescheduled" or "DeepSat GTM declined for tonight"
- *Urgent deadlines bubbling up* — items in =* Upcoming Deadlines= that hit within ~2 days, surfaced as standalone Heads-up items so Craig sees them immediately
- *Active Reminders* (from Phase A's notes.org read) that frame today specifically — "first thing in the morning, register for SOFWeek"

Format: bullet list, one situational note per line, no sub-bullets. Keep each entry to one sentence. If a Heads-up item needs more context, link to the source (email, ticket, prep section) instead of inlining.

Lightweight FYIs (status pings, "FYI we shipped", small acknowledgments) stay in =.ai/session-context.org= and don't surface in Heads-up.

*** Sub-step 7b: Upcoming Deadlines

Write a top-level =* Upcoming Deadlines= section.

Source: scan todo.org for =DEADLINE:= entries plus deadlines mentioned in notes.org or knowledge.org. Filter to roughly the next 4-6 weeks. Order chronologically.

Format: bullet list, one deadline per line, format =- [Day YYYY-MM-DD] — short description=. Mention the owner if it isn't Craig and the deadline still concerns him (e.g., "Subbu owns; Craig's technical content due ahead of this").

Volume control: if more than ~10 deadlines fit the window, narrow the window or surface only the ones that are blocking, externally-imposed, or have non-trivial prep ahead.

Don't duplicate deadlines that are already today's =* Day's Priorities= entries. Day's Priorities is for action; Upcoming Deadlines is for awareness.

*** Sub-step 7c: Next day's Anchor Tasks

Write a top-level =* [Day]'s Anchor Tasks= section. Compute the next day's name from today's date — *don't* skip weekends. For a Friday prep doc this becomes =* Saturday's Anchor Tasks=, for a Saturday prep doc it becomes =* Sunday's Anchor Tasks=, etc. Use known PTO markers if any (a fully-blocked PTO day can be skipped to the next available day).

Source: items Craig is explicitly committing to do tomorrow. Pull from:

- Items planned for today that didn't get done (from Phase 2's Planned vs Actual)
- Items that genuinely fit tomorrow better than today (criterion below)
- Prep work needed before tomorrow's meetings
- Anything Craig flagged during today's session as "I'll do this tomorrow"

*Criterion for pushing an item to tomorrow rather than fitting it today.* Push only if at least one is true:

1. *Hard-blocked today* — waiting on a person, a system, or a deadline that hasn't passed yet
2. *Needs a contiguous block* today's window can't provide
3. *Prep work for a tomorrow-only meeting* (do the prep close to the meeting)
4. *Team-dependent* and the team isn't available today (e.g., Craig's at one location and the team's at another)

If none of those apply, the item stays in today's Day's Priorities and gets a time block in Phase 4. Don't auto-punt independent reading, registration, local-machine work, or "I'll get to it tomorrow" items just because today is a weekend or feels light.

Items further out than tomorrow (Monday-only items written on a Saturday, for example) stay in =todo.org= with appropriate priority and SCHEDULED markers. Don't list them in the prep doc — they'll resurface in the relevant day's prep via Phase 3 sub-step 3a.

Format: bullet list or =** TODO= headings, with optional time estimates (e.g., "— 1.5 hrs"). Each item should be a clear task — passive monitoring or context goes elsewhere (Heads-up or session-context).

This section is the explicit handoff to next-day's Phase 2. If it's empty, write the header with "(none flagged)" so the next day's prep doesn't mistake an empty section for a missing one.

** Phase 8: Archive Older Prep Docs

After the new prep doc is written, archive any prep docs in =inbox/= older than yesterday's. Yesterday's prep doc stays in =inbox/= because the new prep doc may still need to reference it (Planned vs Actual, talking-point carry-forward).

#+begin_src bash
# Move any inbox/*-daily-prep.org file dated before yesterday into the archive.
mv inbox/YYYY-MM-DD-daily-prep.org daily-prep/
#+end_src

The archive lives at =daily-prep/= at repo root. Don't put prep docs in =deepsat/meetings/= — the prep doc covers personal calendar, all 1:1s, and all projects, not just DeepSat work.

If =daily-prep/= doesn't exist yet (new project), create it. If a stale prep doc lives in =assets/= (an older convention), move it to =daily-prep/= as part of this archive pass.

This step keeps =inbox/= clean. The previous-day's prep is the only one that still has consumers.

** Phase 9: Project Extension

If =.ai/project-workflows/daily-prep.org= exists, read and execute its instructions as additional steps appended to this workflow. The project file contains add-ons specific to the project. It is *not* a replacement for this template — it picks up where this workflow's main flow ends.

Surface the extension once per session ("Project has additional daily-prep steps — running them now") so the choice is visible.

This is the project-extension hook from [[file:startup.org][startup.org]]'s workflow discovery rule, made explicit at the workflow level so it's not buried in discovery instructions. Runs in both full-prep and standup-only modes.

* Principles to Follow

** Prep Supports Action
The goal is for Craig to walk into every meeting and task with what he needs. If prep doesn't lead to better outcomes, it's wasted time.

** Craig Drives Priorities
Claude surfaces information and proposes priorities, but Craig decides what matters. Don't assume -- ask.

** Quick Tasks: Just Do Them
If something takes less than 5 minutes, do it during prep rather than scheduling it. Draft the Slack message, create the calendar invite, send the email.

** Respect the Calendar
When proposing time blocks, respect existing commitments across all calendars. Don't double-book. Account for transition time between meetings.

** First-Person Perspective
When preparing 1:1 talking points, frame everything from Craig's perspective -- what does Craig need to communicate, ask, or decide? Not what the other person needs.

* Living Document

Update this workflow based on what works in actual daily prep sessions. Track learnings below.

** Updates and Learnings

*** 2026-02-23: Initial creation
Created during first daily prep session. Validated against tomorrow's schedule (2026-02-24: Vrezh 1:1, Standup/IPM, Product Review, Backlog Planning).

*** 2026-02-23: Use explicit day references, not relative terms
When referring to past meetings or events, always include the explicit day (e.g., "from Monday's meeting" not "from this morning's meeting"). The prep doc may be written the day before and read the day of -- relative references like "this morning" or "today" become ambiguous. Include the day name so Craig doesn't have to calculate days in his head while focused on making a point.

*** 2026-02-23: Prep doc output
The prep is written to =inbox/YYYY-MM-DD-daily-prep.org= where the date is the day being prepped for.
The startup workflow checks for this file and asks whether to open it. Note: need to resolve where the daily prep reference in startup.org lives so template syncing doesn't overwrite it (see todo.org task).

*** 2026-02-23: Check for dependencies between tasks and meetings
Tasks and meetings often depend on each other. SkyFi prep needs to happen before the Vrezh 1:1 so Craig can ask informed questions; Linear learning needs to happen before the backlog planning meeting where they'll use it. Always check for these dependencies and ask Craig when unsure.

*** 2026-02-23: Energy management matters as much as time management
Front-load high-effort, high-stakes work early in the day (about an hour after waking). Save research, reading, and lighter tasks for late afternoon when energy dips. Craig tries to eat lunch and have coffee/tea around 12:30 PM to sustain energy for the afternoon. This principle should guide time block placement alongside calendar constraints.

*** 2026-02-23: Link references in the prep doc
When listing tasks, documents, or directories in the prep doc, include links to the source
(todo.org line numbers, file paths, directories). Craig shouldn't have to search for context
when he's in the middle of a meeting or working through the day.

*** 2026-02-23: Note dependencies between time blocks
When an earlier time block feeds into a later meeting, call it out explicitly in the prep doc
(e.g., "by this point, should have already checked Okta access"). Helps Craig verify he's
on track as the day progresses.

*** 2026-02-23: Prep doc is a living document through the day
Craig may annotate the prep doc with "cj:" comments as he works through it. Process those
when asked or at the start of the next session. Remove the comment markers after acting on them.

*** 2026-02-23: Ask probing questions about task nature
When a task like "SkyFi outreach" could mean either a 5-minute email or a 1-hour call, ask. The answer often splits the task into prep + action, which schedule differently. These questions are very helpful and should be a regular part of the workflow.

*** 2026-03-08: Keep Day's Priorities, drop separate Time Blocking table
The output prep doc should have a "Day's Priorities" section followed by a single chronological
"Meetings / Work Blocks" section that interleaves meetings, prep blocks, and focused work blocks
in time order. No separate Time Blocking table — the chronological Meetings / Work Blocks section
serves that purpose.

*** 2026-03-09: Day's Priorities use org-mode TODO headings, not numbered lists
Each priority is a =** TODO= heading under =* Day's Priorities=, not a numbered list item.
Format: =** TODO Task name — description. Links to todo.org or other files. ~time estimate.=
Do not use bold or italic markup in the prep doc — org headings, TODO keywords, and plain text
provide enough structure.
Mark completed items as =** DONE= with a =CLOSED:= timestamp on the next line.
Order by urgency and priority — most important/time-sensitive first. Craig should be able to
work top-to-bottom and know he's tackling the right thing next.
This makes priorities trackable in org-mode (agenda, todo filtering) and lets Craig toggle
status directly in Emacs as the day progresses.

The workflow phases (identify priorities, propose time blocks) still happen during the prep
conversation — the change is only to the output format.

*** 2026-03-08: Always include Planned vs Actual
Craig finds the Planned vs Actual review table valuable. Always include it in the prep doc
when a previous day's prep doc exists. This is Phase 2 of the workflow and should never be skipped.

*** 2026-04-01: Always use human-readable ticket titles
When referencing Linear tickets (or any issue tracker IDs), always use the human-readable
title with the ID in parentheses — e.g., "Setup Database for dev environment (SE-93)" not
just "SE-93." Craig can't remember what ticket IDs map to, and bare IDs force him to look
them up. Use the Linear MCP tools to fetch the title if needed.

*** 2026-03-27: Standup briefs — only team-visible goals, not personal productivity
Only include work that left Craig's local environment: pushed to a repo, shared with
the team, posted in Slack, changed something in Linear, or shifts what the team believes
or plans. Exclude work whose output lives entirely in Craig's local files (knowledge.org,
todo.org, session notes, transcript processing, local tooling setup, MCP server config).
Filter: "If I didn't mention this, would someone on the team make a worse decision or
duplicate the work?" If no, cut it.

*** 2026-05-12: Day's Priorities entries are thin links to todo.org tasks — never duplicated content
Craig's call. The prep doc's =* Day's Priorities= entries point at todo.org tasks (=** TODO [#X] <title> — [[file:../todo.org::*<title>][todo.org]]= plus a one-line "why today"); all the substance — descriptions, drafts, research, sub-tasks, VERIFY asks, recommended-approach — lives in the matching todo.org task, which Phase 3 creates or updates. Completed-today entries still become dated log headings in the prep doc (the day's record), linking to their durable todo.org home if there is one. Full statement in *Prep Doc Structure ▸ Day's Priorities entries are thin links to todo.org tasks* above. Follow-up: Phase 3 sub-steps 3b–3f still say "add to the prep doc" — reword them to "create/update the todo.org task, link from the prep doc" on the next pass. (Supersedes the 2026-03-09 "Day's Priorities use org-mode TODO headings" entry's implication that the content lives in the prep doc — the headings still use TODO keywords / dated-log headings, but the body is a link.)

*** 2026-05-15: Triage Action items become =:quick:reactive:= todo.org tasks — no grouped Response sub-sections
Craig's call, originally landed in the work project's =triage-intake= workflow on 2026-05-15 and propagated here on 2026-05-16. Each Action item surfaced by Phase 3 sub-steps 3b/3d/3e/3f (email, Slack, Linear, PRs) becomes its own =** TODO [#B] <verb-led description> :quick:reactive:[person]:= in =todo.org=. The Day's Priorities section in the prep doc references it via a thin link when it belongs in today's plan, otherwise the task stays in =todo.org= for later. Replaces the prior pattern of building grouped =** Email Response= / =** Slack Response= / =** Linear Response= / =** PR Review= sub-headings under Day's Priorities — those sub-sections no longer exist. Source mix now lives in the tags on each task, not in the prep doc structure. Full statement in *Prep Doc Structure ▸ Triage Action items become =:quick:reactive:= todo.org tasks* above. (Closes the 2026-05-12 follow-up about rewording sub-steps 3b–3f.)