aboutsummaryrefslogtreecommitdiff
path: root/.ai/protocols.org
blob: 6b1d8731530a49639160d03bca88695331c3e456 (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
#+TITLE: Claude Code Protocols
#+AUTHOR: Craig Jennings & Claude
#+DATE: 2025-11-05

* About This File

This file contains instructions and protocols for how Claude should behave when working with Craig. These protocols are consistent across all projects.

**When to read this:**
- At the start of EVERY session (this is the single entry point)
- Before making any significant decisions
- When unclear about user preferences or conventions

**What's in this file:**
- Directory architecture (.ai/ file/directory map)
- Session management protocols (context files, compacting)
- Terminology and trigger phrases
- User information and preferences
- Git commit requirements
- File format and naming conventions
- Startup instructions (runs .ai/workflows/startup.org)

**What's NOT in this file:**
- Project-specific context (see notes.org)
- Session history (see notes.org)
- Active reminders (see notes.org)
- Pending decisions (see notes.org)

* Directory Architecture

Every project using this template has an =.ai/= directory for Claude tooling and a project-level =docs/= directory for real project documentation.

** =.ai/= (hidden, Claude tooling)

Every file and directory has a defined purpose:

| Item                  | Purpose                                                                        |
|-----------------------+--------------------------------------------------------------------------------|
| =protocols.org=       | Single entry point — behavioral instructions + directory map                   |
|-----------------------+--------------------------------------------------------------------------------|
| =notes.org=           | Project state: context, active reminders, pending decisions                    |
|-----------------------+--------------------------------------------------------------------------------|
| =session-context.org= | Live session state (exists only during active sessions); renamed on wrap-up    |
|-----------------------+--------------------------------------------------------------------------------|
| =sessions/=           | Archived session files (one per session) — =YYYY-MM-DD-HH-MM-description.org=  |
|-----------------------+--------------------------------------------------------------------------------|
| =workflows/=          | Template workflows (synced from claude-templates, never edit in project)       |
|-----------------------+--------------------------------------------------------------------------------|
| =project-workflows/=  | Project-specific workflows (never touched by sync)                             |
|-----------------------+--------------------------------------------------------------------------------|
| =scripts/=            | Template scripts (synced from claude-templates, never edit in project)         |
|-----------------------+--------------------------------------------------------------------------------|
| =project-scripts/=    | Project-specific scripts (never touched by sync; mirrors =project-workflows/=) |
|-----------------------+--------------------------------------------------------------------------------|
| =someday-maybe.org=   | Project ideas backlog                                                          |
|-----------------------+--------------------------------------------------------------------------------|

** =docs/= (visible, real project documentation)

Reserved for actual project documentation — user-facing docs, architecture notes, setup guides, reference material. Not touched by the template sync. May not exist in every project. When Claude generates a project-specific reference doc (e.g., a setup guide, an architecture analysis), it goes here.

* IMPORTANT - MUST DO

** CRITICAL: Always Check the Time with =date= Command

***NEVER GUESS THE TIME. ALWAYS RUN =date= TO CHECK.***

Claude's internal sense of time is unreliable. When mentioning what time it is - whether in conversation, session notes, timestamps, or scheduling - ALWAYS run:

#+begin_src bash
date "+%A %Y-%m-%d %H:%M %Z"
#+end_src

This applies to:
- "What time is it?"
- Session start/end timestamps
- Calculating time until appointments
- Setting alarms
- Any time-related statement

Do NOT estimate, guess, or rely on memory. Just run the command. It takes one second and prevents errors.

** Startup Pull Ordering — Rulesets Before Project

Every session pulls rulesets first, then the local project repo. Rulesets carries the canonical behavioral rules and =.ai/= templates (the old =claude-templates= repo is folded in as a subtree at =rulesets/claude-templates/=); the project pull lands commits pushed from other machines or teammates since the last session.

Resolve any dirty-tree or merge issue at each step before moving on. Both pulls run as =git pull --ff-only= (or =git merge --ff-only= against the fetched upstream), so anything non-trivial — non-fast-forward history, dirty working tree, diverged branches — aborts. Surface the state and stop. Never auto-stash, auto-merge, or auto-rebase; the user resolves the conflict before further work.

Mechanics live in =startup.org= Phase A.0. The rule lives here because it governs the very first action of every session: load the freshest behavioral rules and templates before anything else runs.

** Session Context File — Record + Recovery Anchor

Location during session: =.ai/session-context.org=
Location after wrap-up: =.ai/sessions/YYYY-MM-DD-HH-MM-description.org=

*** Agent-scoped path (=AI_AGENT_ID=)

When two agents share one project at the same time, a single =session-context.org= is a race — each agent's writes clobber the other's. The active path is therefore resolved per agent:

- =AI_AGENT_ID= unset or empty (the normal one-agent-per-project case): =.ai/session-context.org=, exactly as before.
- =AI_AGENT_ID= set: =.ai/session-context.d/<id>.org= (id sanitized to filename-safe chars). Archived at wrap-up to =.ai/sessions/YYYY-MM-DD-HH-MM-<id>-<description>.org= so concurrent agents don't collide on the archive name either.

Resolve the path with =.ai/scripts/session-context-path= rather than hardcoding =.ai/session-context.org=; it prints the right path for the current =AI_AGENT_ID=. Fall back to =.ai/session-context.org= if the script isn't present (older checkouts mid-sync). Everything below — the record/recovery purpose, the update triggers, the startup existence check, the wrap-up rename — operates on that resolved path. The prose says "session-context.org" as the default name; read it as "the resolved active path" when =AI_AGENT_ID= is set.

This file serves two purposes with one mechanism:
1. *Crash recovery* — if the session dies mid-work, the live file is all that's left. On 2026-01-22 a session crashed during a 20-minute design discussion and all context was lost because this file wasn't being updated.
2. *Session archive* — at wrap-up the file is renamed into =.ai/sessions/=, becoming the permanent record. No transcription to notes.org; the file IS the record.

*** File structure

Two top-level sections:

- =* Summary= — Structured distillation written at wrap-up. Subsections: Active Goal, Decisions, Data Collected / Findings, Files Modified, Next Steps. This is what's read at /catch up/ (first 5 most recent session files).
- =* Session Log= — Chronological narrative written /as you go/. Captures the sequence of events, rationale for decisions, dead ends tried, context that doesn't fit neatly into the Summary's sections. Use =** Topic= section headers at natural seams (major sub-tasks, phase changes, long pauses). Timestamps optional — use when genuinely useful.

The Summary lets a future reader scan quickly. The Log preserves the /why/ and the sequence.

*** When to update (Session Log)

*Primary trigger (mechanical).* A turn that called any state-modifying tool — Edit, Write, Agent dispatch, MCP write, or Bash that mutates state (anything beyond pure reads like =git status=, =ls=, =grep=, =cat=) — writes to the Session Log before the closing user-facing message. This is not a judgment call. If the turn changed state, the turn gets a Session Log entry before the response goes out. The entry can be brief: one short paragraph naming what changed and why.

Pure-read turns (only Read, Glob, Grep, or read-only Bash) do not trigger. Conversational turns with no tools do not trigger.

The bullets below are not optional supplements — they all change state and so the primary trigger already covers them. They appear explicitly because they are the high-loss moments where missing the write is most expensive:

- A decision was reached ("we agreed on X, not Y")
- A workflow phase completed, or a new phase is starting
- A substantive finding, diagnosis, or root cause identified
- Before starting a new subtask or changing direction
- Before context compaction (predictable event — save first)
- Before long-running or blocking tool calls — agent spawns, builds, rsync/ssh loops, MCP calls to external services. You could be waiting minutes; if anything crashes during the wait, everything since the last save is gone.
- Before destructive or irreversible operations — =rm -rf=, =git reset --hard=, force-push, package removal, database drops. If the op succeeds and something breaks afterward, you need to know what state you caused.

*** Safety net

If 5 user turns pass without appending to the Log, save anyway. Semantic triggers should catch most cases; this fallback covers judgment failures.

*** What counts as "updating"

Actually write to the file using Edit or Write. Not "I should update it." Not "I'll update soon." Write it now.

Prose form. Narrate the work: what changed, why, what was tried, what came next. Don't try to fit Session Log entries into the Summary's section template — that's for wrap-up.

*** At session start

Check if =.ai/session-context.org= exists:
- *Exists* → previous session was interrupted. Read it immediately to recover context.
- *Doesn't exist* → fresh session; create the file with a skeletal structure (title, =* Summary= with empty subsections, =* Session Log= header) when the first Log-worthy event occurs.

*** After compaction

Review =session-context.org= to confirm no essential context was lost, then continue.

*** At session end (wrap-up)

The wrap-it-up workflow handles this:
1. Write/refine the =* Summary= section by reading the =* Session Log=
2. Pick a 4-6 word description of the work (like a git-commit-message-series summary)
3. Rename =.ai/session-context.org= → =.ai/sessions/YYYY-MM-DD-HH-MM-description.org=
4. Commit + push

The file /persists/ under its new name. It is not deleted. The absence of =.ai/session-context.org= is the signal that the last session wrapped up cleanly.

** NEVER =cd= Into Directories You Will Delete

If you =cd= into a directory and then delete that directory, the shell's working directory becomes invalid. All subsequent commands will fail silently (exit code 1) with no useful error message. The only fix is to restart the session.

***Rule:*** Always use absolute paths for file operations in temporary directories. Never =cd= into extraction directories, build directories, or any directory that will be cleaned up.

This caused a session break on 2026-02-06 when an extraction directory was =cd='d into and then deleted during cleanup.

** Cross-Project Boundary — Stop and Ask

If a request targets a file or task under a *different* project's =.ai/= scope than the current session (cwd is one project, the argument names another project's =todo.org=, =inbox/=, or similar), stop and ask before doing the work: "this looks like it belongs to <other project>'s session — do it from here, or switch projects?"  Inline numbered options, no popup.

Each project's =.ai/= is the scope boundary: =protocols.org=, =session-context.org=, =sessions/=, =notes.org=, =todo.org=, =inbox/=, plus the project's memory dir at =~/.claude/projects/<encoded-cwd>/memory/=.  Crossing without flagging pollutes the current session's log with the other project's content and drops memories into the wrong dir.  If the user confirms "do it from here," write a handoff file at =<other-project>/inbox/YYYY-MM-DD-handoff-from-<this-project>-<topic>.org= so the other project's next session picks it up.

Canonical rule: =~/code/rulesets/claude-rules/cross-project.md=.

** Working-Files Convention — =working/<task-slug>/= for In-Progress Artifacts

Every in-progress task that produces files (drafts, source documents, diagrams, scripts, sub-deliverables) gets a dedicated subdirectory under =<project-root>/working/=, named after the task. All artifacts for that task live in that subdirectory until the task is marked done.

When the task ships, files are **renamed individually** (standard form: =YYYY-MM-DD-<task-slug>-<descriptor>.<ext>=) and **moved flat** into the appropriate permanent home (typically =assets/= or an area-specific =<area>/assets/=). The working subdirectory is then empty and gets deleted.

***Never rename the directory itself as a substitute for filing.*** The point is to keep =assets/= flat-searchable — a nested =assets/old-tech-deck-2026/slide.png= is harder to find than =assets/2026-05-18-tech-deck-vol2-slide-04-diagram.png=.

When the user starts a new task that will produce file artifacts, propose the =working/<task-slug>/= path before creating any files. Add or update the inbound link in =todo.org= to point at the working dir. When the user marks the task done, list every file, propose renames + permanent homes, move flat after confirmation, delete the empty subdir, update inbound links.

Canonical rule: =~/code/rulesets/claude-rules/working-files.md=.

** Inbox Monitoring Cadence — Check at Task Boundaries

Check =inbox/= at every task boundary (after finishing a unit of work, before reporting back or asking "what's next") — not only at startup or when asked. Handoffs arrive mid-session; this keeps them from piling up unseen. The check is one command:

#+begin_src bash
.ai/scripts/inbox-status -q
#+end_src

Exit 1 means handoffs are pending — process them per =process-inbox.org=. For each accepted handoff, the act-vs-file rule: *act now* when it's clear, bounded, low-risk, in-scope, and cheaper than deferring — just do it, no asking; *file* otherwise — ask first, with filing as option 1 and "do it now" as option 2; *ask* if unsure. Exception: a proposal to change a shared asset (template workflow, rule, skill, synced script) or a substantive convention never silently acts now — it goes through process-inbox's Skeptical Review and its approval (or park) step. Always reply to a handoff's sender (confirm on accept, the why on reject). Full process, the reply discipline, and the opt-in background-monitor =/loop= recipe live in =monitor-inbox.org=.

** Recursive Reads — Honor =.aiignore=

Before a naive recursive read or glob of a project tree (file inventories, "what's in this repo", broad greps), skip the noise: dependency trees (=node_modules/=, =.venv/=), build output (=dist/=, =build/=, =coverage/=), language caches (=__pycache__/=, =.pytest_cache/=, =*.pyc=), editor/OS cruft, and generated token/OAuth artifacts. These waste tokens and skew project summaries even when gitignored — a recursive read sees the disk, not git.

If the project root has a =.aiignore= (gitignore syntax), honor its patterns; it carries project-specific additions. rulesets ships one as the canonical example. Absent a file, assume the defaults above.

Lockfile policy: skip lockfiles on agent reads (large and low-signal). That's about what agents read, not what git tracks for reproducibility.

* Important Terminology

** "Let's run the [X] workflow" vs "I want to create an [X] workflow"

These phrases mean DIFFERENT things!

*** "Let's run/do the [workflow name] workflow"
This means: **Execute the existing workflow** for that process.

*Example:*
- "Let's run the refactor workflow" -> Read .ai/workflows/refactor.org and guide through workflow
- "Let's do a refactor workflow" -> Same as above

*** "I want to create an [X] workflow"
This means: **CREATE a new workflow definition** for doing X (meta-work).
This does **NOT** mean "let's DO X right now."

*Example:*
- "I want to create a refactor workflow" -> Create .ai/workflows/refactor.org using create-workflow process

When Craig uses this phrasing, trigger the create-workflow process from .ai/workflows/create-workflow.org. New workflows go to =.ai/project-workflows/= by default. Only put a workflow in =.ai/workflows/= (and =~/code/rulesets/claude-templates/.ai/workflows/=) if Craig explicitly says it's for all projects.

** "Wrap it up" / "That's a wrap" / "Let's call it a wrap"

Execute the wrap-up workflow (details in Session Protocols section below):
1. Write session notes to notes.org
2. Git commit and push all changes
3. Valediction summary

* User Information

** Calendar Management

Three ways to access Craig's calendars: Google Calendar MCP (preferred, both personal + work accounts), gcalcli (fallback, personal only), Emacs org files (read-only viewer).

For tool recipes, authentication details, and credentials, see [[file:references/calendar-reference.org][calendar-reference.org]].


** GPG Keys

Craig has two GPG key pairs configured:

| Email                           | Key ID                                     | Purpose        |
|---------------------------------+--------------------------------------------+----------------|
| =c@cjennings.net=               | =3388FB17E147A563558F2CEC0E56F0A5B832F070= | Default key    |
|---------------------------------+--------------------------------------------+----------------|
| =craigmartinjennings@gmail.com= | =1A1F6932A25357793FB2B4C51C4D081632A5CDA7= | Gmail identity |
|---------------------------------+--------------------------------------------+----------------|

Both are RSA 4096-bit, passphrase-protected, no expiry.

*** Encrypting files
#+begin_src bash
gpg -e --default-recipient-self file.json          # encrypt to Craig's default key
gpg -e -r craigmartinjennings@gmail.com file.json  # encrypt to specific key
gpg -c file.json                                    # symmetric (passphrase only, no key)
#+end_src

*** Decrypting files
#+begin_src bash
gpg -d file.json.gpg > file.json       # decrypt (pinentry GUI handles passphrase)
#+end_src

*** Notes
- GPG pinentry uses a GUI dialog — works from Claude Code (no TTY needed)
- =--default-recipient-self= uses the =c@cjennings.net= key
- Prefer key-based encryption over symmetric for project secrets

** Signature Image

A transparent-background PNG scan of Craig's handwritten signature lives at
=~/pictures/cj-sig-transparent.png= (324×213, cropped), with a higher-resolution
version at =~/pictures/cj-sig-no-background.png= (1536×1024). Both are symlinks
into the archsetup stow dotfiles (=~/code/archsetup/dotfiles/common/pictures/=),
so they're present on every machine. RGBA, transparent background; composites
cleanly over a form line.

Default for signing documents is still Craig signing by hand in Xournal++. Only
overlay this image onto a PDF (or other document) when Craig *explicitly asks
for it on a specific document* — never sign for him on your own initiative. The
=edit-pdf= workflow (project-level, where present) has the reportlab snippet for
stamping it.

** Sending Email

Craig has three mail accounts. *Default to cmail for personal / non-work email* — reach for it unless the message is work-related.

| Account | Address                              | Use for                              |
|---------+--------------------------------------+--------------------------------------|
| =cmail= | =c@cjennings.net= (Proton Bridge)    | *Default.* Personal / non-work mail. |
|---------+--------------------------------------+--------------------------------------|
| =dmail= | =craig.jennings@deepsat.com= (Gmail) | Work mail.                           |
|---------+--------------------------------------+--------------------------------------|
| =gmail= | =craigmartinjennings@gmail.com=      | Third account, rarely the right one. |
|---------+--------------------------------------+--------------------------------------|

*The tool is =cmail-action send=* (symlinked into =~/.local/bin=, on PATH from any project). Don't hand-roll MIME or pipe raw messages through =msmtp= — the script builds the message, threading, and attachments for you.

#+begin_src bash
# simple
cmail-action send --to addr@example.com --subject "Subject" --body "One-liner body."
# body from a file (preferred for anything multi-line)
cmail-action send --to addr@example.com --subject "Subject" --body-file /tmp/draft.txt
# with attachments (repeatable --attach, MIME type auto-detected)
cmail-action send --to addr@example.com --subject "Subj" --body-file /tmp/draft.txt --attach a.pdf --attach b.png
# a threaded reply
cmail-action send --to addr@example.com --subject "Re: ..." --body-file /tmp/draft.txt \
  --cc someone@example.com --in-reply-to "<msgid>" --references "<msgid>"
#+end_src

=cmail-action= handles the receive/triage side too (=list-unread=, =read=, =mark-read=, =star=, =trash=). For the full guided flow (validate the recipient against =contacts.org=, confirm before sending, verify delivery), run the =send-email= workflow; for a known recipient, the one-liner above is enough.

** Task List Location
Craig's global task list is available at: =/home/cjennings/org/roam/inbox.org=

Use this to:
- See all the tasks that he's working on outside of projects like this one

**Note:** Some projects may have a project-specific task file (e.g., =todo.org= at project root). Check notes.org for project-specific task locations.

** Working Style

*** General Preferences
- Prefers detailed preparation before high-stakes meetings
- Values practice/role-play for negotiations and general learning
- Makes decisions based on principles and timeline arguments
- Prefers written documentation over verbal agreements

*** Emacs as a Primary Working Tool
- Craig uses Emacs as his primary tool (most everything Craig does is inside Emacs)
- Consider Emacs packages along with other software when recommending software solutions
- Look for ways to streamline routine work with Emacs custom code if no packages exist

*** Wayland Environment (No XWayland)
Craig runs a pure Wayland setup (Hyprland) and avoids XWayland/Xorg apps.

- Clipboard: Use =wl-copy= and =wl-paste= (NOT =xclip= or =xsel=)
- Window management: Use Hyprland commands (NOT =xkill=, =xdotool=, etc.)
- Prefer Wayland-native tools over X11 equivalents
- Open URLs in browser: Use =google-chrome-stable "URL" &>/dev/null &=
  - The =&>/dev/null &= is required to detach the process and suppress output
  - Without it, the command may appear to hang or produce no result

*** Shell aliases (=ls= → =exa=)
Craig's shell aliases =ls= to =exa=, which prints nothing to non-TTY pipes (e.g. when capturing =ls= output in a Bash tool call). The result looks like the directory is empty when it isn't.

- Always use =\ls= (or =command ls=) when capturing output. The backslash bypasses the alias.
- Applies to =ls -la=, =ls -t=, glob expansions piped through =ls=, and any =ls= invocation whose output gets read programmatically.
- Symptom if forgotten: the Bash tool returns empty output and you mistakenly conclude the directory is empty.

** Miscellaneous Information
- Craig currently lives in New Orleans, LA
- Craig's phone number: 510-316-9357
- Craig maintains a remote server at the cjennings.net domain
- This project is in a git repository which is associated with a remote repository on cjennings.net

** Setting Alarms / Reminders

Use Craig's =notify= script with the =at= daemon for persistent reminders.

**IMPORTANT:** Always check the current date and time (=date=) before setting alarms to ensure accurate calculations.

**Default to =--persist= for any page meant to get Craig's attention** (alarms, reminders, meeting alerts). A transient notification auto-dismisses after a few seconds, so a page that fires while Craig is away from his desk is missed entirely. =--persist= keeps it on screen until he dismisses it. Drop the flag only for a genuinely low-value informational ping.

*** Setting an alarm
#+begin_src bash
echo 'notify alarm "Title" "Message" --persist' | at 10:55am
#+end_src

*** Examples
#+begin_example
echo 'notify alarm "Standup" "Daily standup in 5 minutes" --persist' | at 10:55am
echo 'notify alarm "BP Reading" "Time to take BP" --persist' | at 2:00pm
echo 'notify alert "Meeting" "Ryan call starting" --persist' | at 11:25am
#+end_example

*** Notify types available
- =alarm= - Alarm clock icon, alarm sound
- =alert= - Yellow exclamation, attention tone
- =info= - Blue info icon, confident tone
- =success= - Green checkmark, pleasant chime
- =fail= - Red X, warning tone

Full usage: =notify --help= or see =~/.local/bin/notify=

*** Managing alarms
- =atq= - list all scheduled alarms
- =atrm [number]= - remove an alarm by its queue number

* Session Protocols

** CRITICAL: Git Commit Requirements

***IMPORTANT: ALL commits must be made as Craig, NOT as Claude.***

***CRITICAL: NO Claude Code or Anthropic attribution ANYWHERE in commits.***

When creating commits:

1. **Author Identity**: NEVER commit as Claude. All commits must use Craig's identity.
   - Git will use the configured user.name and user.email
   - Do NOT modify git config
   - **ABSOLUTELY NO** Co-Authored-By lines
   - **ABSOLUTELY NO** "Generated with Claude Code" text
   - **ABSOLUTELY NO** Anthropic attribution of any kind
   - Write commits AS CRAIG, not as Claude Code

2. **Commit Message Format**:
   - Use project-specific commit format if defined
   - Otherwise: concise subject line and terse description only
   - **ONLY subject line and terse description - NO Claude Code attribution**
   - Keep messages clear and informative

3. **No Claude-tooling artifacts**: Commit messages describe project changes only — the meta-process of how work got shipped stays out of public git history.
   - **ABSOLUTELY NO** mentions of =notes.org=, =session-context.org=, =.ai/sessions/=, =todo.org=, "session wrap-up", or session timestamps (e.g., "Session YYYY-MM-DD HH:MM → ...")
   - Subject lines must NEVER start with =session:= as a conventional-commit type — use =docs:=, =refactor:=, =fix:=, =feat:=, =chore:=, etc. (real change categories)
   - When a wrap-up commit bundles many changes from a session, describe what /shipped/ (e.g., =refactor: extract RAID logic + add bats testing infrastructure=), not that a session happened
   - Same spirit as the no-Claude-attribution rule: the tooling stays invisible in =git log=

4. **Validation**:
   - Claude should validate commit message format before committing
   - Ensure no AI attribution or tooling-artifact references appear anywhere in commit

** IMPORTANT: Reminders Protocol

When starting a new session:
- Check "Active Reminders" section in notes.org
- Remind Craig of outstanding tasks he's asked to be reminded about
- This ensures important follow-up actions aren't forgotten between sessions

When Craig says "remind me" about something:
1. Add it to Active Reminders section in notes.org
2. If it's something he needs to DO, also add to the todo.org file in the project root as an org-mode task (e.g., =* TODO [description]=). If this project does not have a todo.org at the project root, alert Craig and offer to create it.
3. If not already provided, ask for the priority and a date for scheduled or deadline.

** Workflows: "Let's run/do the [workflow name] workflow"

When Craig says this phrase:

1. **Check =.ai/workflows/= for match**
   - If exact match found: Read and guide through process
   - Example: "refactor workflow" -> read .ai/workflows/refactor.org

2. **Check =.ai/project-workflows/= for match**
   - If exact match found: Read and guide through process

3. **Fuzzy match across both directories:** Ask for clarification
   - Example: User says "empty inbox" but we have "inbox-zero.org"
   - Ask: "Did you mean the 'inbox zero' workflow, or create new 'empty inbox'?"

4. **No match at all:** Offer to create it
   - Say: "I don't see '[workflow-name]' yet. Create it using create-workflow process?"
   - If yes: Run create-workflow — new workflows go to =.ai/project-workflows/= by default

** Long-Running Process Status Updates

When monitoring a long-running process (rsync, large downloads, builds, VM tests, etc.), follow this protocol:

***At Start:***
1. Run =date= to get accurate time
2. Announce the task/job beginning
3. Provide best-guess ETA for completion

#+begin_example
**14:30** - Starting ISO build. ETA: ~10 minutes.
#+end_example

***Every 5 Minutes:***
- Check progress and display status in format: =HH:MM= - terse description - ETA

#+begin_example
**14:35** - ISO build: packages installed, creating squashfs. ETA: ~5 min.
**14:40** - ISO build: squashfs 95% complete. ETA: ~1 min.
#+end_example

***At Completion:***
1. Send notification via notify script:
   #+begin_src bash
   notify success "Task Complete" "Description of what finished" --persist
   #+end_src
   Use =fail= type instead of =success= if the task failed. Keep =--persist=. The completion ping exists to reach Craig when he's away from the screen, so it must wait for him rather than auto-dismiss.
2. Provide summary of success or failure

#+begin_example
**14:42** - ISO build complete. Size: 2.0G. Ready for testing.
#+end_example

***Guidelines:***
- Always run =date= for accurate timestamps
- Keep progress descriptions terse but informative
- Update ETA as job progresses
- If ETA cannot be determined, say "ETA unknown" rather than guessing wildly

***Why This Matters:***
- Craig may be working on other things while waiting
- Status updates provide confidence the process is still running
- ETAs help with planning (e.g., "I have time for coffee" vs "stay close")
- Sound notification alerts Craig when he's away from the screen
- If something stalls, the updates make it obvious

** "Wrap it up" / "That's a wrap" / "Let's call it a wrap"

When Craig says any of these phrases (or variations), execute the wrap-up workflow: [[file:workflows/wrap-it-up.org][wrap-it-up.org]]. Four steps:

1. *Finalize the Summary* in =.ai/session-context.org= (populate the 5 subsections from the Session Log)
2. *Rename* =.ai/session-context.org= → =.ai/sessions/YYYY-MM-DD-HH-MM-description.org=
3. *Git commit + push* to all remotes (see Git Commit Requirements)
4. *Valediction* — brief, warm, specific closing

The absence of =.ai/session-context.org= after wrap-up is the signal that the session ended cleanly. If the file is still there at the next session start, the previous session was interrupted.

** Where to put generated documents

Claude needs to add information to =.ai/notes.org=. For large amounts of information:

- **Claude tooling context** (session state, workflows, internal research that only Claude needs) → break out into a separate file in =.ai/=, link it from =.ai/notes.org=
- **Real project documentation** (setup guides, reference material, architecture notes — anything Craig might point other people at) → place in =docs/= at project root, not =.ai/=. Link from =.ai/notes.org= if Claude needs to reference it.

**Project-specific decision:** Should =.ai/= be committed to git or added to =.gitignore=?
- Ask Craig on first session if not specified
- Code projects (Emacs packages, libraries) usually gitignore =.ai/= — session notes are private, not part of the codebase
- Personal/documentation projects usually commit =.ai/= — the project history IS the project
- =docs/= (when it exists) is typically tracked either way — it's real documentation

**The gitignore set follows that same decision.** A project that gitignores =.ai/= (the code-project case) gitignores the whole personal-tooling set: =.ai/=, =.claude/=, =CLAUDE.md=, =AGENTS.md=. =.claude/= is rulesets-owned — copies of =claude-rules/*.md= plus the language bundle's rules, hooks, and settings — and re-synced from rulesets on every startup, so git isn't how it travels between machines; ignoring it also keeps those private rule copies out of the repo, which ignoring =CLAUDE.md= alone would miss. A track-mode project (personal/doc repos, or a team repo that shares config with teammates who don't run rulesets) tracks the set instead. =install-ai.sh= writes the full set at bootstrap in gitignore mode; =scripts/sweep-gitignore-tooling.sh= backfills it idempotently across existing gitignore-mode projects when the set grows.

**Credential-leak concern: gate it on project type, not on the credential itself.** A tracked secret, token, or credentials doc is only a public-leak risk where the repo can reach a public remote — that is, *code projects pushed to public GitHub*, which is exactly why those gitignore =.ai/= and =.claude/=. For *personal / documentation projects* (the =~/projects/= set: elibrary, home, finances, health, philosophy, etc.), the git remote is a private single-user repo on =cjennings.net=, so tracked credentials inside =.ai/= files are fine — that's the design, the project history IS the project. Do NOT raise a leak warning or suggest gitignoring a secret for these. When the question "is this a leak / should we gitignore this secret?" comes up, decide it on *which kind of project and remote* this is, never on the mere presence of a credential in a tracked file.

**When to break out documents:**
- If notes.org's Project-Specific Context section gets very large (> 1500 lines) — split into focused reference docs
- Session records go in =.ai/sessions/= automatically (one file per session via wrap-up workflow) — never mixed into notes.org

* File Format Preferences

** ALWAYS Use Org-Mode Format

Craig uses Emacs as primary tool. **ALWAYS** create new documentation files in =.org= format, not =.md= (markdown).

*Rationale:*
- Org-mode files are well-supported in Emacs
- Can be easily exported to any other format (HTML, PDF, Markdown, etc.)
- Better integration with user's workflow

*Exception:* Only use .md if specifically requested or if file is intended for GitHub/web display where markdown is expected.

** NEVER Use Spaces in Filenames

**ALWAYS** use hyphens (=-=) to separate words in filenames. Underscores (=_=) are also acceptable.

*Rationale:*
- Spaces cause problems with links across different operating systems
- User works with Mac, Windows, Linux, and potentially other systems
- Hyphens create more reliable, portable filenames
- Easier to work with in command-line tools

*Examples:*
- Good: =project-meeting-notes.org=
- Good: =change-log-2025-11-04.md=
- Bad: =project meeting notes.org=
- Bad: =change log 2025.11.04.md=

* File Naming Conventions

** Files Too Large to Read

PDFs or other files that are too large for Claude to read should be prefixed with =TOOLARGE-= to prevent read errors that halt the session.

Example:
- Original: =assets/large-architectural-plans.pdf=
- Renamed: =assets/TOOLARGE-large-architectural-plans.pdf=

** Unreadable Binary Files (.docx Format)

Binary .docx files cannot be read directly by Claude. When encountering these:
- Convert to markdown format using pandoc: =pandoc file.docx -o file.md=
- Keep the original .docx file for reference
- Work with the converted .md file for analysis and editing

** CRITICAL: Always Keep Links Current

Many documents are linked in org files using org-mode =file:= links. Craig relies on these links being valid at all times.

**MANDATORY WORKFLOW - When renaming or moving ANY file:**

1. **BEFORE renaming:** Search ALL org files for references to that file
   - Use grep or search tools to find both filename and partial matches
   - Check in TODO items and event log sections

2. **Rename or move the file**

3. **IMMEDIATELY AFTER:** Update ALL =file:= links to new path/filename
   - Update links in task files
   - Update links in event logs
   - Update links in reference sections

4. **Verify:** Test a few updated links to ensure they point to valid files

Example workflow:
#+begin_example
# Step 1: Search before renaming
grep -rn "2025-10-15-invoice.pdf" *.org

# Step 2: Rename the file
mv documents/2025-10-15-invoice.pdf documents/2025-10-15-vendor-invoice.pdf

# Step 3: Update all references in affected .org files
# Edit to change:
#   file:documents/2025-10-15-invoice.pdf
# to:
#   file:documents/2025-10-15-vendor-invoice.pdf

# Step 4: Verify links work
#+end_example

*Why This is Critical:*
- Org files are primary task tracking and reference system
- Event logs document complete history with file references
- Craig depends on clicking links to access documents quickly
- Broken links disrupt workflow and make documentation unreliable

**NEVER rename or move files without updating links in the same session.**

* Session Start - AUTOMATIC

At the start of EVERY session, run [[file:workflows/startup.org][.ai/workflows/startup.org]]. Do NOT ask — just do it automatically.