diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-26 01:57:48 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-26 01:57:48 -0500 |
| commit | f9c72c817290bb5433e593b2a8d1cfaa25431d20 (patch) | |
| tree | fed103aec3faf75624a2a969fd67dea71e501a4d /.ai/workflows/triage-intake.personal-calendar.org | |
| parent | 98382929852b213f8dc8b1ba720cc0d1861159b6 (diff) | |
| download | rulesets-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.org | 53 |
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). |
