aboutsummaryrefslogtreecommitdiff
path: root/.ai/workflows/triage-intake.personal-calendar.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-26 01:57:48 -0500
committerCraig Jennings <c@cjennings.net>2026-05-26 01:57:48 -0500
commitf9c72c817290bb5433e593b2a8d1cfaa25431d20 (patch)
treefed103aec3faf75624a2a969fd67dea71e501a4d /.ai/workflows/triage-intake.personal-calendar.org
parent98382929852b213f8dc8b1ba720cc0d1861159b6 (diff)
downloadrulesets-f9c72c817290bb5433e593b2a8d1cfaa25431d20.tar.gz
rulesets-f9c72c817290bb5433e593b2a8d1cfaa25431d20.zip
refactor(workflows): split triage-intake into engine + source plugins
The triage-intake workflow had every source baked into one file, so adding or changing a source meant editing the workflow itself. I replaced it with a source-agnostic engine plus per-source plugins named triage-intake.<source>.org. The engine carries the anchor/sentinel logic, the four-bucket model, the Phase A-D orchestration, the todo.org persistence convention, and the exit criteria. Each source's scan, classify, render, and action knowledge moved into its own plugin. Four general plugins ship in the template: personal-gmail, personal-calendar, cmail, and github-prs. Project-specific sources live in the project's .ai/project-workflows/ and are never synced. Phase 0 globs both directories so a project source can't silently drop out of the sweep. I taught INDEX.org and the startup workflow-discovery drift check the namespace. A file matching <engine>.*.org is a plugin of that engine, not an orphan, and gets no trigger entry of its own. A "run the triage-intake workflow" request routes to the engine, never to a plugin.
Diffstat (limited to '.ai/workflows/triage-intake.personal-calendar.org')
-rw-r--r--.ai/workflows/triage-intake.personal-calendar.org53
1 files changed, 53 insertions, 0 deletions
diff --git a/.ai/workflows/triage-intake.personal-calendar.org b/.ai/workflows/triage-intake.personal-calendar.org
new file mode 100644
index 0000000..bf7d543
--- /dev/null
+++ b/.ai/workflows/triage-intake.personal-calendar.org
@@ -0,0 +1,53 @@
+#+TITLE: Triage Intake — Personal Calendar Source
+#+AUTHOR: Craig Jennings & Claude
+#+DATE: 2026-05-26
+
+# Source plugin for the triage-intake engine. See triage-intake.org for the
+# contract and the Phase A-D orchestration. This file declares ONE source.
+
+* Source: personal-calendar
+:PROPERTIES:
+:ORDER: 30
+:ENABLED: mcp google-calendar present
+:ANCHOR: iso8601
+:SUBAGENT_OVER: 40
+:END:
+
+** Scan
+
+Calendar isn't an unread queue — it's two signals: what's *coming up soon* and what *changed since last check*. Pull the near-horizon window for the personal account, then let Classify split it by the anchor.
+
+#+begin_src text
+mcp__google-calendar__list-events account="personal" timeMin="<now-iso8601>" timeMax="<now+36h-iso8601>" singleEvents=true orderBy="startTime"
+#+end_src
+
+The event objects carry =created=, =updated=, and the attendee =responseStatus=. The engine supplies =<anchor-iso8601>= so Classify can flag events whose =updated= is after the anchor as "new/changed since last check." (=list-events= filters by start-time window, not by updated-since, so the change detection happens in Classify, not the query.)
+
+** Classify
+
+Calendar leans *FYI* — most upcoming events are just awareness. The Action cases are narrow:
+
+- *Action:*
+ - A new invite with =responseStatus=needsAction= (Craig hasn't replied).
+ - A reschedule or cancellation of an event Craig had — =updated= after the anchor and the time/status changed.
+ - An event starting within ~2h that Craig might have lost track of.
+- *FYI:* upcoming events today/tomorrow, unchanged since last check.
+- *Noise-keep / trash:* declined events, all-day informational banners, automated holiday entries — tally only, no action.
+
+Surface "changed since last check" prominently — a reschedule that slips by is the expensive miss.
+
+** Render
+
+#+begin_example
+**Calendar (personal) — N upcoming, M changed since last check.**
+- Action: <invites needing a response, reschedules, imminent events>
+- Upcoming: <today/tomorrow events, terse>
+#+end_example
+
+Omit the block if nothing upcoming and nothing changed.
+
+** Actions
+
+- respond :: =mcp__google-calendar__respond-to-event= account="personal" eventId=<event-id> responseStatus=<accepted|declined|tentative>
+
+Read-only otherwise — triage surfaces calendar state; it doesn't create or move events (that's the add/edit-calendar-event workflows).