aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ai/workflows/triage-intake.org78
-rw-r--r--claude-templates/.ai/workflows/triage-intake.org78
-rw-r--r--docs/design/2026-06-15-auto-triage-intake-spec.org43
-rw-r--r--todo.org2
4 files changed, 201 insertions, 0 deletions
diff --git a/.ai/workflows/triage-intake.org b/.ai/workflows/triage-intake.org
index b257f2d..7d1290f 100644
--- a/.ai/workflows/triage-intake.org
+++ b/.ai/workflows/triage-intake.org
@@ -168,6 +168,81 @@ If Craig has been silent for a while after Phase D and the surface looks closed-
This rule prevents the failure mode where the workflow self-declares done and the next exchange has to relitigate what state things are in.
+* Auto mode (unattended monitoring)
+
+Auto mode is a self-running variant of the engine for when Craig is away from the desk but wants tight awareness — a loop that runs the standard sweep on a short interval, *accumulates* findings rather than mutating state, and hands Craig a gated checkpoint to commit the batch. It composes two things: the *delivery* (a =/loop= in the live session) and the *behavior* (accumulate-don't-mutate sweeps with a checkpoint). The one-shot run above is unchanged; auto mode is an additional way to run the same Phase 0 / A-D engine.
+
+** Trigger and delivery
+
+- "auto triage" / "auto triage-intake" / "watch the desk" / "monitor the triage" — start auto mode.
+- Default interval *20 minutes*; Craig sets it.
+
+Auto mode runs as a =/loop= in the *live session*, not a detached cron job:
+
+#+begin_src
+/loop 20m run an auto-mode triage-intake sweep per triage-intake.org
+#+end_src
+
+Running in the live session means MCP auth (Slack, Gmail, Linear) is inherited from the session — the headless-auth wall that blocks a detached cron run does not apply. A durable cross-session schedule is out of scope here; that belongs to the morning-ops orchestrator, which can later invoke auto mode's accumulate behavior as its triage limb. The close/stop commands below require a live session by design.
+
+** Preconditions and Close-out
+
+Auto mode borrows the inbox-monitor gates (=monitor-inbox.org=): do not start on a dirty worktree or a red test suite — a close's batch commit would otherwise sweep up unrelated changes — and leave the tree clean and green when the loop stops. Surface a blocker with inline numbered options per =interaction.md= and wait.
+
+** A sweep: accumulate, don't mutate
+
+Each sweep runs Phase 0 (load *both* plugin dirs — the loud requirement still holds) and Phases A-D's scan / classify / synthesize, but performs *none* of the normal run's mutations:
+
+- Does NOT advance the sentinel. The scan window grows from the last *close* until the next close: every sweep scans from the existing sentinel up to now, so nothing between sweeps is dropped.
+- Does NOT write =todo.org= Action tasks — accumulates them for the close.
+- Does NOT take mail actions (trash / mark-read / star).
+- Does NOT commit.
+- DOES update an active daily-prep in Update mode and re-open it on change (per =daily-prep.org=).
+- DOES report, deltas-only, with loud scan-failure banners (Phase C rules unchanged).
+
+** End-of-sweep output — two sections
+
+1. *Deltas* — what changed since the *previous sweep* (the standard Phase C summary scoped to the inter-sweep delta; one line if nothing: "HH:MM sweep: no changes").
+2. *Responses awaiting your acknowledgment* — every Slack reply, email, or message directed at Craig that he hasn't acknowledged or had the agent answer. A *running list carried forward across sweeps* until Craig acks each item or closes the triage. An away user's first need is "who's waiting to hear back from me," which a delta-only sweep loses the moment it scrolls past.
+
+** The unacked list — durable state
+
+The awaiting-acknowledgment list lives in =.ai/triage-intake-unacked.org=, so it survives a session crash, a =/clear=, or a restart — the away-from-desk case auto mode exists for. It's project-local state, tracked the same way as the sentinel (=.ai/last-triage-intake=), created on first need.
+
+Shape — one =** = heading per awaiting item:
+
+#+begin_example
+#+TITLE: Triage Intake — Responses Awaiting Acknowledgment
+# Maintained by triage-intake auto mode. One heading per item; acked items are removed.
+
+** Dana — 2pm reschedule invite
+:PROPERTIES:
+:SOURCE: personal-calendar
+:LOCATOR: <event id or thread url — the dedupe key>
+:SINCE: 2026-06-15 10:42
+:END:
+She's waiting on a yes/no to the move.
+#+end_example
+
+- *Add* — a sweep appends any new directed-at-Craig response not already listed, deduped on =LOCATOR=.
+- *Carry forward* — every sweep re-renders the full list in its second section, whether or not it changed this sweep.
+- *Ack* — "ack <item>" (e.g. "ack the Dana thread") removes that heading; "ack all" clears the list.
+- *Close* — a close empties the list as part of processing (each item is either actioned or filed).
+
+** Close and stop — the checkpoint
+
+The mutations are gated behind two commands:
+
+- *"close the triage"* — run the full close: take the accumulated mail actions, add the accumulated Action items to =todo.org= as =:quick:reactive:= tasks (asking Craig the questions a normal Phase C/D would), empty the unacked list, then *advance the sentinel* — capture the close run's Phase A timestamp, do the mutations, write that timestamp to =.ai/last-triage-intake= exactly as a normal run does (per "Capture the Phase A timestamp") — and commit + push the batch. Then *keep looping* (next sweep on the normal interval). This is the "flush the batch and carry on" checkpoint.
+- *"stop the triage"* — the same close processing, then *stop the loop* and revert to manual (on-demand) triage.
+
+A close is the only point auto mode advances the sentinel or commits. Between closes the engine state is untouched — that is what makes a 20-minute sweep cheap and non-destructive, and it preserves the engine invariant: the sentinel still means "everything before this timestamp has been scanned," it just advances once per close instead of once per run.
+
+** Why a separate mode
+
+The standard engine is one-shot and mutating — right for an at-the-desk "what's new?" glance, wrong for unattended polling: run every 20 minutes it would advance the sentinel past unprocessed items, spray reactive todos, take mail actions, and commit noise without review. Auto mode separates the cheap, frequent *watching* from the deliberate, gated *committing*, and adds the away-user's missing primitive — the running unacked-responses list.
+
+
* Reference
** Source Plugin Contract
@@ -314,6 +389,9 @@ Update the engine as the orchestration pattern evolves; update a plugin as its s
*** Updates and Learnings
+**** 2026-06-15: Auto mode (unattended monitoring)
+Added a self-running mode for when Craig is away but wants tight awareness — a =/loop= in the live session running accumulate-don't-mutate sweeps with "close the triage" / "stop the triage" as the gated checkpoint. Born the morning Craig cleared his day for a family emergency and wanted the desk watched while in and out. Design decisions (work-project proposal, ratified by Craig 2026-06-15): the unacked-responses list is durable in =.ai/triage-intake-unacked.org= (survives a crash/clear, the away-from-desk case it exists for); the sentinel advances only at close, preserving the scanned-before invariant; delivery is an in-session loop so MCP auth is inherited (a detached cron schedule belongs to the morning-ops orchestrator, not here, because of the headless-auth wall); it stays a mode of this engine, distinct from but reusable by that orchestrator.
+
**** 2026-05-01: Initial creation
Extracted from daily-prep's Phase 3 pattern as a standalone, lightweight, between-meetings sweep.
diff --git a/claude-templates/.ai/workflows/triage-intake.org b/claude-templates/.ai/workflows/triage-intake.org
index b257f2d..7d1290f 100644
--- a/claude-templates/.ai/workflows/triage-intake.org
+++ b/claude-templates/.ai/workflows/triage-intake.org
@@ -168,6 +168,81 @@ If Craig has been silent for a while after Phase D and the surface looks closed-
This rule prevents the failure mode where the workflow self-declares done and the next exchange has to relitigate what state things are in.
+* Auto mode (unattended monitoring)
+
+Auto mode is a self-running variant of the engine for when Craig is away from the desk but wants tight awareness — a loop that runs the standard sweep on a short interval, *accumulates* findings rather than mutating state, and hands Craig a gated checkpoint to commit the batch. It composes two things: the *delivery* (a =/loop= in the live session) and the *behavior* (accumulate-don't-mutate sweeps with a checkpoint). The one-shot run above is unchanged; auto mode is an additional way to run the same Phase 0 / A-D engine.
+
+** Trigger and delivery
+
+- "auto triage" / "auto triage-intake" / "watch the desk" / "monitor the triage" — start auto mode.
+- Default interval *20 minutes*; Craig sets it.
+
+Auto mode runs as a =/loop= in the *live session*, not a detached cron job:
+
+#+begin_src
+/loop 20m run an auto-mode triage-intake sweep per triage-intake.org
+#+end_src
+
+Running in the live session means MCP auth (Slack, Gmail, Linear) is inherited from the session — the headless-auth wall that blocks a detached cron run does not apply. A durable cross-session schedule is out of scope here; that belongs to the morning-ops orchestrator, which can later invoke auto mode's accumulate behavior as its triage limb. The close/stop commands below require a live session by design.
+
+** Preconditions and Close-out
+
+Auto mode borrows the inbox-monitor gates (=monitor-inbox.org=): do not start on a dirty worktree or a red test suite — a close's batch commit would otherwise sweep up unrelated changes — and leave the tree clean and green when the loop stops. Surface a blocker with inline numbered options per =interaction.md= and wait.
+
+** A sweep: accumulate, don't mutate
+
+Each sweep runs Phase 0 (load *both* plugin dirs — the loud requirement still holds) and Phases A-D's scan / classify / synthesize, but performs *none* of the normal run's mutations:
+
+- Does NOT advance the sentinel. The scan window grows from the last *close* until the next close: every sweep scans from the existing sentinel up to now, so nothing between sweeps is dropped.
+- Does NOT write =todo.org= Action tasks — accumulates them for the close.
+- Does NOT take mail actions (trash / mark-read / star).
+- Does NOT commit.
+- DOES update an active daily-prep in Update mode and re-open it on change (per =daily-prep.org=).
+- DOES report, deltas-only, with loud scan-failure banners (Phase C rules unchanged).
+
+** End-of-sweep output — two sections
+
+1. *Deltas* — what changed since the *previous sweep* (the standard Phase C summary scoped to the inter-sweep delta; one line if nothing: "HH:MM sweep: no changes").
+2. *Responses awaiting your acknowledgment* — every Slack reply, email, or message directed at Craig that he hasn't acknowledged or had the agent answer. A *running list carried forward across sweeps* until Craig acks each item or closes the triage. An away user's first need is "who's waiting to hear back from me," which a delta-only sweep loses the moment it scrolls past.
+
+** The unacked list — durable state
+
+The awaiting-acknowledgment list lives in =.ai/triage-intake-unacked.org=, so it survives a session crash, a =/clear=, or a restart — the away-from-desk case auto mode exists for. It's project-local state, tracked the same way as the sentinel (=.ai/last-triage-intake=), created on first need.
+
+Shape — one =** = heading per awaiting item:
+
+#+begin_example
+#+TITLE: Triage Intake — Responses Awaiting Acknowledgment
+# Maintained by triage-intake auto mode. One heading per item; acked items are removed.
+
+** Dana — 2pm reschedule invite
+:PROPERTIES:
+:SOURCE: personal-calendar
+:LOCATOR: <event id or thread url — the dedupe key>
+:SINCE: 2026-06-15 10:42
+:END:
+She's waiting on a yes/no to the move.
+#+end_example
+
+- *Add* — a sweep appends any new directed-at-Craig response not already listed, deduped on =LOCATOR=.
+- *Carry forward* — every sweep re-renders the full list in its second section, whether or not it changed this sweep.
+- *Ack* — "ack <item>" (e.g. "ack the Dana thread") removes that heading; "ack all" clears the list.
+- *Close* — a close empties the list as part of processing (each item is either actioned or filed).
+
+** Close and stop — the checkpoint
+
+The mutations are gated behind two commands:
+
+- *"close the triage"* — run the full close: take the accumulated mail actions, add the accumulated Action items to =todo.org= as =:quick:reactive:= tasks (asking Craig the questions a normal Phase C/D would), empty the unacked list, then *advance the sentinel* — capture the close run's Phase A timestamp, do the mutations, write that timestamp to =.ai/last-triage-intake= exactly as a normal run does (per "Capture the Phase A timestamp") — and commit + push the batch. Then *keep looping* (next sweep on the normal interval). This is the "flush the batch and carry on" checkpoint.
+- *"stop the triage"* — the same close processing, then *stop the loop* and revert to manual (on-demand) triage.
+
+A close is the only point auto mode advances the sentinel or commits. Between closes the engine state is untouched — that is what makes a 20-minute sweep cheap and non-destructive, and it preserves the engine invariant: the sentinel still means "everything before this timestamp has been scanned," it just advances once per close instead of once per run.
+
+** Why a separate mode
+
+The standard engine is one-shot and mutating — right for an at-the-desk "what's new?" glance, wrong for unattended polling: run every 20 minutes it would advance the sentinel past unprocessed items, spray reactive todos, take mail actions, and commit noise without review. Auto mode separates the cheap, frequent *watching* from the deliberate, gated *committing*, and adds the away-user's missing primitive — the running unacked-responses list.
+
+
* Reference
** Source Plugin Contract
@@ -314,6 +389,9 @@ Update the engine as the orchestration pattern evolves; update a plugin as its s
*** Updates and Learnings
+**** 2026-06-15: Auto mode (unattended monitoring)
+Added a self-running mode for when Craig is away but wants tight awareness — a =/loop= in the live session running accumulate-don't-mutate sweeps with "close the triage" / "stop the triage" as the gated checkpoint. Born the morning Craig cleared his day for a family emergency and wanted the desk watched while in and out. Design decisions (work-project proposal, ratified by Craig 2026-06-15): the unacked-responses list is durable in =.ai/triage-intake-unacked.org= (survives a crash/clear, the away-from-desk case it exists for); the sentinel advances only at close, preserving the scanned-before invariant; delivery is an in-session loop so MCP auth is inherited (a detached cron schedule belongs to the morning-ops orchestrator, not here, because of the headless-auth wall); it stays a mode of this engine, distinct from but reusable by that orchestrator.
+
**** 2026-05-01: Initial creation
Extracted from daily-prep's Phase 3 pattern as a standalone, lightweight, between-meetings sweep.
diff --git a/docs/design/2026-06-15-auto-triage-intake-spec.org b/docs/design/2026-06-15-auto-triage-intake-spec.org
new file mode 100644
index 0000000..1c7cd94
--- /dev/null
+++ b/docs/design/2026-06-15-auto-triage-intake-spec.org
@@ -0,0 +1,43 @@
+#+TITLE: Proposed engine addition — Auto mode (auto triage-intake)
+#+DATE: 2026-06-15
+
+* What this adds
+
+A new *mode* of the triage-intake engine: *auto mode* (auto triage-intake). It's a self-running monitor for when Craig is away from the desk but wants tight awareness — a loop that runs the standard triage on a short interval, accumulates rather than mutating, and hands Craig a controlled checkpoint to commit the batch.
+
+Origin: 2026-06-15, the morning Craig had to clear his day for a family emergency and wanted the desk watched while he was in and out. He asked for 20-minute sweeps that summarize what's come in for him, with an explicit command to process and commit the batch.
+
+* The mode
+
+** Cadence
+A loop (CronCreate / =/loop=) fires the triage on an interval — default *20 minutes*. Craig sets the interval.
+
+** Accumulate, don't mutate (the core difference from a normal run)
+A normal triage run writes the sentinel, creates =:quick:reactive:= todos, takes mail actions on confirmation, and is a one-shot. An auto-mode *sweep* does none of the mutations:
+
+- Does NOT advance the sentinel — the scan window grows from the last *close* until the next close, so nothing is dropped between sweeps.
+- Does NOT create todo.org tasks — accumulates them (in the session log) for the close.
+- Does NOT take mail actions (trash / mark-read / star).
+- Does NOT commit.
+- DOES run the full plugin scan, DOES update an active daily-prep (Update mode) and re-open it on change, DOES report.
+
+** End-of-sweep output
+Each sweep ends with two short sections:
+1. *Deltas* — what changed since the last sweep (one line if nothing).
+2. *Responses awaiting your acknowledgment* — every Slack reply, email, or message directed at the user that he hasn't explicitly acknowledged or had the agent answer. This is a *running list carried forward* across sweeps until the user acks each item or closes the triage. It exists because an away user's main need is "who's waiting to hear back from me," which a delta-only sweep loses the moment it scrolls past.
+
+** Close / stop commands (the checkpoint)
+The mutations are gated behind two user commands:
+
+- *"close the triage"* — finish the mail + sentinel processing, add all accumulated todos (asking the user questions along the way), commit and push, then *keep looping* (next sweep on the normal interval). This is the "flush the batch and carry on" checkpoint.
+- *"stop the triage"* — the same close processing, then *stop the loop* and revert to manual triage (run only when asked).
+
+* Why it's worth adding to the engine
+
+The standard engine is one-shot and mutating, which is right for an at-the-desk "what's new?" glance. It's wrong for unattended monitoring: running it every 20 minutes would spray reactive todos, advance the sentinel past unprocessed items, and commit noise without review. Auto mode separates the cheap, frequent *watching* from the deliberate, gated *committing* — and adds the away-user's missing primitive, the running unacknowledged-responses list.
+
+* Companion notes
+
+- The interval loop is the delivery mechanism (CronCreate session-only, or a durable schedule); the mode is the behavior. They compose.
+- "Responses awaiting acknowledgment" tracking needs a small piece of state. In a session it can live in the session-context log; if the engine wants it durable across sessions, a tiny =.ai/triage-unacked.org= (or similar) is the natural home — flagged as a design choice for the rulesets side to decide.
+- Deltas-only reporting (the 2026-06-11 ruling) and loud scan-failure surfacing both still apply inside each sweep.
diff --git a/todo.org b/todo.org
index 3ab2430..9d5abcf 100644
--- a/todo.org
+++ b/todo.org
@@ -186,6 +186,8 @@ Expected: all four behave per the spec; any miss promotes to a bug task. (Agent-
:END:
A scheduled headless morning run chaining the existing pieces: startup checks, the triage-intake scan, a system health check — producing the prep doc plus a report and a notify ping, with all remediation propose-only. Staged adoption from the 2026-06-11 insights report's "Self-Healing Daily Ops Orchestrator": read-only first; promote individual routine remediations to auto only after each has a track record. Known blockers to design around: headless MCP auth (interactively-authenticated servers are absent in cron runs) and the consent boundary (triage Phase D, anything destructive).
+The triage limb can reuse triage-intake's *auto mode* (added 2026-06-15, see [[file:.ai/workflows/triage-intake.org]]) — its accumulate-don't-mutate sweep is the propose-only behavior this orchestrator wants. Auto mode itself runs in-session (inherited MCP auth); the orchestrator is the durable headless schedule, so the headless-auth blocker above is the part still on this task to solve.
+
** TODO [#C] Build =create-documentation= skill for high-quality project/product docs :feature:
:PROPERTIES:
:LAST_REVIEWED: 2026-06-12