aboutsummaryrefslogtreecommitdiff
path: root/.ai/workflows/startup.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-06 21:59:52 -0500
committerCraig Jennings <c@cjennings.net>2026-05-06 21:59:52 -0500
commitd81b23ad6b6e437dfe3c338a00a4be39bc555146 (patch)
tree2d4b0d7890fd1fc70d81282b81fed2808c28a106 /.ai/workflows/startup.org
parent201377f57430ef28d02e703a2191434bbee55c75 (diff)
downloadrulesets-d81b23ad6b6e437dfe3c338a00a4be39bc555146.tar.gz
rulesets-d81b23ad6b6e437dfe3c338a00a4be39bc555146.zip
chore(ai): initialize project notes and Claude tooling surfaces
Replace the seed notes.org with project-specific context (layout, install modes, task tracker location, recent inflection point). Bring in the synced template surfaces (protocols, workflows, scripts, references, retrospectives, someday-maybe) as tracked content for this content/documentation project.
Diffstat (limited to '.ai/workflows/startup.org')
-rw-r--r--.ai/workflows/startup.org178
1 files changed, 178 insertions, 0 deletions
diff --git a/.ai/workflows/startup.org b/.ai/workflows/startup.org
new file mode 100644
index 0000000..19045d3
--- /dev/null
+++ b/.ai/workflows/startup.org
@@ -0,0 +1,178 @@
+#+TITLE: Startup Workflow
+#+AUTHOR: Craig Jennings & Claude
+#+DATE: 2026-04-25
+
+* Overview
+
+This workflow runs automatically at the beginning of EVERY session. It gives Claude project context, syncs templates, discovers available workflows, and determines session priorities. Do NOT ask Craig if he wants to run it — just execute it.
+
+The workflow is structured into four phases. *Phase A.0* is a sequential pre-flight; *Phase A and Phase B should each run as a single batch of parallel tool calls* — sending one message with multiple Bash / Read calls in it, not sequential round-trips. Phase C is interactive and runs sequentially.
+
+* The Workflow
+
+** Phase A.0 — Pre-flight: refresh claude-templates and project repo (sequential, runs first)
+
+Two refreshes happen before Phase A. Both are sequential pre-steps, not part of Phase A's parallel batch. Run them as two separate Bash calls in order.
+
+*** Refresh claude-templates
+
+Phase A's rsync commands copy from =~/projects/claude-templates/= into the project's =.ai/= directory. If that source repo is behind its own =origin/main=, the rsync silently reverts committed template updates in the project, dirtying the working tree. Pull claude-templates first so the rsync runs against current content.
+
+#+begin_src bash
+ct="$HOME/projects/claude-templates"
+if [ -d "$ct/.git" ]; then
+ if (cd "$ct" && git diff --quiet --ignore-submodules HEAD -- 2>/dev/null); then
+ (cd "$ct" && git pull --ff-only origin main 2>&1) | tail -3
+ else
+ echo "claude-templates: dirty working tree — using as-is, skipping pull"
+ fi
+else
+ echo "claude-templates: not a git checkout — skipping"
+fi
+#+end_src
+
+Behavior:
+- *Clean working tree* → fast-forward pull. =git pull --ff-only= refuses any merge or rebase, so the operation is either a no-op (already current) or a clean advance.
+- *Dirty working tree* → skip the pull. Don't auto-stash and don't auto-merge — those would either lose work or invite conflicts at the worst possible moment (session start).
+- *Non-fast-forward history* → =--ff-only= aborts with an error. Surface that to the user; the rsync still proceeds against the working tree as-is.
+
+*** Refresh project repo (cwd)
+
+Pull down whatever's been pushed to the project's remotes since the last session — could be commits Craig made on another machine, teammate pushes, or any branch that advanced upstream. Without this, the session starts from a stale local view and any new branch work happens on top of an out-of-date base.
+
+#+begin_src bash
+if [ -d .git ]; then
+ git fetch --all --prune 2>&1 | tail -5
+
+ current=$(git symbolic-ref --short HEAD 2>/dev/null)
+ dirty=0
+ if ! git diff --quiet --ignore-submodules HEAD -- 2>/dev/null \
+ || [ -n "$(git status --porcelain --untracked-files=no)" ]; then
+ dirty=1
+ fi
+
+ git for-each-ref --format='%(refname:short)' refs/heads/ | while read branch; do
+ upstream=$(git rev-parse --abbrev-ref "${branch}@{upstream}" 2>/dev/null) || continue
+ counts=$(git rev-list --left-right --count "${upstream}...${branch}" 2>/dev/null) || continue
+ behind=$(echo "$counts" | cut -f1)
+ ahead=$(echo "$counts" | cut -f2)
+
+ if [ "$behind" -gt 0 ] && [ "$ahead" -eq 0 ]; then
+ if [ "$branch" = "$current" ]; then
+ if [ "$dirty" -eq 0 ]; then
+ git merge --ff-only "$upstream" >/dev/null 2>&1 \
+ && echo " $branch: fast-forwarded $behind commits"
+ else
+ echo " $branch: behind $behind — dirty tree, fetched only"
+ fi
+ else
+ git fetch . "${upstream}:${branch}" >/dev/null 2>&1 \
+ && echo " $branch: fast-forwarded $behind commits (non-checkout)"
+ fi
+ elif [ "$ahead" -gt 0 ] && [ "$behind" -gt 0 ]; then
+ echo " $branch: diverged ($ahead ahead, $behind behind) — leaving alone"
+ fi
+ done
+else
+ echo "project repo: not a git checkout — skipping"
+fi
+#+end_src
+
+Behavior, per branch:
+- *Behind only, current branch, clean tree* → =git merge --ff-only= advances HEAD.
+- *Behind only, current branch, dirty tree* → fetched but not advanced. Surface so Craig can ff manually after dealing with the dirty state.
+- *Behind only, non-checkout branch* → =git fetch . upstream:branch= advances the ref without touching the working tree.
+- *Diverged* (ahead and behind) → leave alone. Surface for Craig to resolve. Don't auto-rebase or auto-merge.
+- *Ahead only* or *up to date* → silent no-op.
+
+Phase A's rsyncs depend on the claude-templates refresh completing first. The project-repo refresh has no such dependency, but lives here for symmetry with the wrap-up's "push all local branches" step.
+
+** Phase A — Initial fan-out (one parallel batch)
+
+These calls have no dependencies on each other. Issue them all together in one message:
+
+1. =date "+%A %Y-%m-%d %H:%M %Z"= — accurate timestamp.
+2. Check whether =.ai/session-context.org= exists (e.g. =[ -e .ai/session-context.org ] && echo present || echo absent=).
+3. =rsync -a ~/projects/claude-templates/.ai/protocols.org .ai/protocols.org=.
+4. =rsync -a --delete ~/projects/claude-templates/.ai/workflows/ .ai/workflows/=.
+5. =rsync -a --delete ~/projects/claude-templates/.ai/scripts/ .ai/scripts/=.
+6. =\ls -t .ai/sessions/ 2>/dev/null | head -5= — list 5 most recent session files. The backslash bypasses any =ls= alias in the user's profile. Without it, bare =ls -t= silently returns no output under =exa= (a common =ls= replacement) — which makes a sessions directory full of files look empty, and the agent then skips Phase B step 2.
+7. =\ls -la inbox/ 2>/dev/null= — inventory the inbox. Same reason for the backslash escape, applied uniformly across the Phase A =ls= calls.
+8. =cross-agent-status 2>/dev/null || true= — snapshot of pending cross-agent messages across local projects. This is layer A of the cold-start design from =cross-agent-comms.org=: pending messages from other agents (delivered while no session was active here) get surfaced on session start. The =|| true= keeps Phase A from failing if =cross-agent-status= isn't installed yet — older projects without the script still boot cleanly. If HALT is active, =cross-agent-status= prints a banner; surface that prominently in Phase C.
+9. Read =.ai/notes.org= — Project-Specific Context, Active Reminders, Pending Decisions sections (skip About This File).
+10. Read =.ai/project-workflows/startup-extras.org= if it exists.
+
+Notes on the rsync commands:
+- Trailing slashes on both source and destination matter — they tell rsync to sync /contents/ rather than nest a directory inside.
+- =--delete= on the directory syncs lets retired template files actually disappear from each project on next startup.
+- protocols.org is a single file, no =--delete= needed.
+
+Rationale: Every call in Phase A is read-only or writes to a distinct path. Running them sequentially wastes round-trips; running them in parallel gives Claude the complete starting picture in one round-trip.
+
+** Phase B — Dependent fan-out (one parallel batch)
+
+These calls depend on Phase A outputs, but are independent of each other. Issue them as a single parallel batch once Phase A returns:
+
+1. *Read =.ai/session-context.org= if Phase A reported it exists.* The file is the crash-recovery anchor — if it's there, the previous session was interrupted and the context lives only in this file.
+2. *Read each of the 5 most recent session files* from Phase A's =\ls -t .ai/sessions/= output. Read just the =* Summary= section of each — not the full file. The Summary gives Active Goal / Decisions / Data Collected / Findings / Files Modified / Next Steps. That's enough to pick up where things left off. Drill into a specific =* Session Log= later only if you need the /why/ or sequence on something. *If Phase A's listing came back empty, sanity-check with =\ls -la .ai/sessions/= before treating empty as definitive — sessions/ should normally be populated, and an empty result usually means the listing got swallowed somewhere, not that the directory is genuinely empty.*
+3. *Read each new inbox file* from Phase A's =\ls -la inbox/= output. For =.eml= files, defer to Phase C — those need the extract script (below) rather than a raw Read.
+4. *Process pending cross-agent messages.* For each project with a pending count >0 in Phase A's =cross-agent-status= output (typically the current project; cross-project pending is surfaced too but only acted on if the user asks), run =cross-agent-recv <message-file>= on the file path =cross-agent-status= named. The script returns a structured decision (=process= / =dedup= / =query= / =reject=) per the protocol. For =process=, read the message body to determine the action. For =query=, prepare a clarifying reply. For =reject=, surface to user with the reason. For =dedup=, no action — silent retry already handled. Surface all decisions in Phase C alongside other findings.
+
+Rationale: Reads are independent and benign. Batching them means the whole session-history view + inbox view lands in one round-trip instead of one per file.
+
+** Phase C — Synthesis + interactive
+
+This phase touches the user and runs sequentially:
+
+1. *Surface findings from Phase A and B:*
+ - If =session-context.org= existed, summarize what was in flight at the crash point and ask whether to resume.
+ - Surface Active Reminders from notes.org immediately.
+ - Mention Pending Decisions from notes.org.
+ - Briefly note significant template updates noticed during sync (new workflows, protocol changes).
+ - *Surface pending cross-agent messages.* If =cross-agent-status= reported any pending messages, list them with their =cross-agent-recv= decision (process / query / reject) per file. For =process= messages in this project's inbox, propose handling now or after the current task. For pending in other projects, mention the count so the user knows to switch projects when ready. If HALT was active, surface that prominently — cross-agent activity is paused until =cross-agent-resume= clears it.
+2. *Process inbox if non-empty.* Mandatory — don't ask, just do it. For each file: determine action, recommend filing, get approval, move. For =.eml= files use the extract script (not raw Read):
+ #+begin_src bash
+ # View mode — print metadata and body, extract attachments alongside EML
+ python3 .ai/scripts/eml-view-and-extract-attachments.py inbox/message.eml
+
+ # Pipeline mode — extract, auto-rename, refile to output dir, clean up
+ python3 .ai/scripts/eml-view-and-extract-attachments.py inbox/message.eml --output-dir assets/target-dir/
+ #+end_src
+ The script handles metadata extraction, HTML-to-text conversion, attachment extraction, and auto-renaming to =YYYY-MM-DD-HHMM-Sender-TYPE-Description.ext=. See [[file:../scripts/eml-view-and-extract-attachments-readme.org][EML script readme]].
+3. *Execute project-specific startup extras* (the contents of =.ai/project-workflows/startup-extras.org= read in Phase A). If the file didn't exist, skip.
+4. *Ask about priorities.* "What would you like to work on, or is there something urgent you need?"
+ - If urgent: proceed immediately.
+ - If not: surface the top 3 priority A or B tasks in todo.org plus recent work as context.
+
+Rationale: User-facing work and decisions can't be parallelized — they have to happen one at a time so the user can react.
+
+* Workflow discovery (on demand, not at startup)
+
+Two directories hold workflows:
+- =.ai/workflows/= — template workflows (synced from claude-templates, never edit in project).
+- =.ai/project-workflows/= — project-specific workflows (never touched by sync).
+
+When the user says "let's run/do the [X] workflow" (or otherwise references a workflow by topic):
+
+1. *Read =.ai/workflows/INDEX.org=.* It maps trigger phrases to workflow filenames so you don't have to read each workflow's "When to Use" section to route. Project-workflows aren't in the index — handle those via =ls= in step 2.
+2. *List both directories:* =ls -1 .ai/workflows/ .ai/project-workflows/ 2>/dev/null=.
+3. *Drift check.* Compare the =.org= files in =.ai/workflows/= against the entries in INDEX.org (excluding INDEX.org itself). If an index entry points at a deleted file, or a file in the directory has no index entry, surface the mismatch to the user and offer to update INDEX.org. Don't silently route around it.
+4. *Match the request* against the index trigger phrases first, then against project-workflow filenames if no index hit.
+5. *Read and execute* the matching file.
+6. *No match* → offer to create via =create-workflow=; new workflows go to =.ai/project-workflows/= and project-specific ones don't go in INDEX.org.
+7. *Project extension.* As one of the very last steps in the matched workflow's flow, check if =.ai/project-workflows/= contains a file with the same name as the template that just ran. If yes, read and execute it as *additional* steps appended to the workflow — not a replacement. The project file contains add-on steps that pick up where the template's main flow ends. Surface the extension once per session ("Project has additional steps for send-email.org — running them now"). Only applies when the matched workflow came from =.ai/workflows/=; project-only workflows have no template to extend. This mirrors the startup-extras.org pattern: projects extend template behavior without forking the template repo.
+
+The index is the catalog; the directory is the truth. Drift between them is a bug — catching it on demand keeps the index honest without paying the read cost on every session.
+
+* Common Mistakes
+
+1. *Running Phase A sequentially.* Send all Phase A calls in one message — sequential rsync + ls + read costs round-trips for nothing.
+2. *Reading the entire notes.org file* — only Project-Specific Context, Active Reminders, Pending Decisions.
+3. *Skipping template sync* — projects fall behind on rule changes.
+4. *Skipping Phase A.0* — rsync runs against a stale claude-templates checkout and silently reverts committed template updates in the project's =.ai/=, dirtying the working tree at session start.
+5. *Auto-stashing or auto-merging in Phase A.0* — don't. If claude-templates has uncommitted edits or a non-fast-forward history, leave it alone and let the rsync run against the working tree as-is.
+6. *Not checking for session-context.org* — lose context from crashed sessions.
+7. *Forgetting to surface Active Reminders* — Craig misses critical items.
+8. *Asking if Craig wants inbox processed* — it's mandatory, not optional.
+9. *Announcing "session start complete"* — just begin working on the chosen task.
+10. *Reading full session files instead of just the Summary section* — wastes context for past noise that lives in the Session Log.