aboutsummaryrefslogtreecommitdiff
path: root/.ai/workflows
diff options
context:
space:
mode:
Diffstat (limited to '.ai/workflows')
-rw-r--r--.ai/workflows/inbox.org2
-rw-r--r--.ai/workflows/open-tasks.org25
-rw-r--r--.ai/workflows/task-audit.org15
3 files changed, 41 insertions, 1 deletions
diff --git a/.ai/workflows/inbox.org b/.ai/workflows/inbox.org
index c442d17..5fc855f 100644
--- a/.ai/workflows/inbox.org
+++ b/.ai/workflows/inbox.org
@@ -114,6 +114,8 @@ The item extends a task already filed. Update the parent TODO's body with a date
** File as TODO
Substantive but waits, or needs design/triage before implementation. Add the TODO under =* <Project> Open Work= with priority + tags per the priority-scheme check (core §6). Body summarizes the proposal and links the inbox content if it's been moved to =docs/design/=. Delete the inbox file (or move it to =docs/design/= first if the content survives).
+*Blocking-dependency handoff.* A special shape: another project sends a note that *this* project's work is blocking one of theirs ("your task X is blocked on us — we need Y"). File or link the owning task, tag it =:blocker:=, and name the requesting project in the body (see the cross-project dependency convention in =todo-format.md=). The =:blocker:= tag makes =open-tasks.org= surface that task *first*, since clearing it unblocks the other project. Dedup against an existing task rather than filing a duplicate. When the work later lands, drop =:blocker:= and notify the waiting project (=inbox-send <their-project> --text "Delivered: <what> — you're unblocked."=) so it can lift its own =:blocked:=.
+
** Defer
Rename in place to =inbox/PROCESSED-<original-filename>= and add a brief comment line at the top: =# Deferred YYYY-MM-DD: <condition>=. Don't accumulate deferred items indefinitely — sweep them on a future process pass when the condition is met or the deferral has aged out.
diff --git a/.ai/workflows/open-tasks.org b/.ai/workflows/open-tasks.org
index fe782d6..4ba29dd 100644
--- a/.ai/workflows/open-tasks.org
+++ b/.ai/workflows/open-tasks.org
@@ -176,6 +176,10 @@ Next Mode answers two questions in one output: "what matters most right now?" (t
Apply the prioritization cascade in order. Stop at the first matching step. This is the importance/urgency answer.
+*Exclude blocked tasks.* A task tagged =:blocked:= has an unmet cross-project dependency (its body names the project and the work owed, per =todo-format.md=). It can't be worked until that other project delivers, so it is *never* the cascade recommendation — skip it at every cascade step below. Blocked tasks are surfaced on their own in Step 3 so the stalled dependency stays visible instead of silently dropping out of view.
+
+*Surface blocking tasks first.* The mirror of the above: a task tagged =:blocker:= is holding up work in *another* project (its body names which project and what's owed, per =todo-format.md=). Clearing it unblocks that project, so it carries borrowed urgency — surface it at the *top* of the cascade recommendation regardless of its own priority cookie, ahead of the normal In-Progress / deadline / priority order. When several =:blocker:= tasks exist, lead with the one blocking the most, or the longest. This is the "do the thing that unblocks someone else first" rule; a =:blocker:= task left at its own low priority is exactly how a cross-project dependency stalls.
+
**** 1. In-Progress Tasks
- Look for tasks marked =DOING= or partially complete.
- *If found:* Recommend that task (always finish what's started).
@@ -228,11 +232,22 @@ Within each row, pick a single task per the same-level tie-breakers above (block
The friction filter is the override path. When the cascade winner is partially blocked, hardware-dependent, or simply too large for the user's current state, one of the friction rows is what they pick instead.
+*** Step 3 — Blocked-on-other-projects surface
+
+Independently of the cascade and the friction filter, collect every open task tagged =:blocked:=. These are tasks this project can't advance until another project delivers; surfacing them keeps a cross-project dependency from rotting at low priority on the other side — the exact failure the tag exists to prevent (a blocked task whose blocker is a =[#D]= in another project sits forever otherwise).
+
+For each blocked task, read its body for the blocking project and what's owed, and present one line: the task, the blocking project, and what that project owes. Then offer — per blocked task — to nudge the blocker: an =inbox-send <project> --text= note naming what's needed and why it's blocking, so the dependency gets attention in the project that owns it. Don't send without the user's go.
+
+If no =:blocked:= tasks exist, omit this surface entirely (the common case).
+
*** Output Format
-Pair the cascade recommendation with the friction block beneath it. Recommendation-at-item-1 convention applies to the friction rows — quick+solo first, since it's the strongest low-friction pick.
+Pair the cascade recommendation with the friction block beneath it, and the blocked-on-other-projects surface (Step 3) beneath that when any blocked task exists. Recommendation-at-item-1 convention applies to the friction rows — quick+solo first, since it's the strongest low-friction pick.
#+begin_example
+Unblocks other projects (do these first):
+- ai-term wrap-teardown companion — :blocker:, unblocks rulesets (the three ai-term functions)
+
Cascade recommendation (importance/urgency):
- Fix org-noter reliability — [#A], Method 1, 8/18 complete, blocks daily reading/annotation
@@ -240,17 +255,25 @@ If you want lower friction instead:
1. Quick + solo: Bump linter config — [#C] :quick:solo:, ~15 min
2. Quick: Confirm new dirvish setup — [#B] :quick:, needs your eye
3. Solo: Refactor config-utilities — [#B] :solo:, bounded but multi-hour
+
+Blocked on other projects (can't advance until the blocker delivers):
+- Wrap-teardown feature — blocked by emacsd: ai-term companion functions — nudge?
#+end_example
+The =:blocker:= surface sits at the very top — clearing one of those is the highest-leverage thing on the list, since it frees work in another project. Omit it when no =:blocker:= task exists (the common case).
+
Include for each row:
- Task name / description.
- Priority + tag cluster.
- One-line reasoning. For the cascade row, name which cascade step matched. For friction rows, an effort hint when one is obvious.
- Progress indicator (for V2MOM-structured todos) on the cascade row only.
+- For a =:blocker:= row: the project it unblocks and what's owed (from the task body).
+- For a blocked row: the blocking project and what it owes (from the task body), plus the nudge offer.
**** Edge cases
- *Empty friction block.* If no =:quick:= or =:solo:= tagged tasks exist in the open set, omit the friction block entirely. Present only the cascade recommendation.
+- *No =:blocker:= tasks.* Omit the "Unblocks other projects" surface entirely (the common case) — show it only when a task carries the =:blocker:= tag.
- *Dedupe.* If the cascade recommendation IS the same task as one of the friction rows (e.g. it's =:quick:solo:= and also won the cascade), show it once at the top with both labels. Don't list it twice.
- *Decline behavior.* If the user declines the cascade recommendation, drop straight to the friction block as the natural next prompt. Do not fall through to lower-cascade-tier tasks; the friction filter IS the override.
diff --git a/.ai/workflows/task-audit.org b/.ai/workflows/task-audit.org
index 67ce496..94b99da 100644
--- a/.ai/workflows/task-audit.org
+++ b/.ai/workflows/task-audit.org
@@ -84,6 +84,21 @@ For every STALE task, edit it in the main thread:
Follow =todo-format.md= for completion mechanics (depth-based DONE vs dated-rewrite) and the working-files / link-hygiene rules when moving artifacts.
+** Phase C.5 — Consolidate related tasks (interactive)
+
+Phase C's *Consolidate duplicates* bullet folds tasks that track the *same* thing. This step is the broader case: tasks that aren't duplicates but are really *one effort* fragmented across the list. A spread-out effort — several tasks all circling "make the tooling agent-agnostic," say — is harder to see, plan, and finish as a whole than one task, or one parent with the pieces as children.
+
+After the Phase C edits, read the open-task set as a whole and look for *clusters*: tasks that share a goal, a subsystem, or an obvious sequence. Use judgment over the task bodies, not a keyword heuristic — adjacency is a semantic call, and a brittle title-match both misses real clusters and invents false ones.
+
+For each cluster, surface it to Craig (inline numbered options per =interaction.md=, no popup) with a recommendation, offering the two shapes:
+
+- *Merge* — fold the cluster into one task when the members are genuinely the same work split up (near-duplicates, or steps with no independent value). The merged task keeps the strongest priority, unions the type tags, and absorbs each member's body as a dated note or a short list; the absorbed tasks close per =todo-format.md= (a =**= task → =CANCELLED= + =CLOSED:= with a one-line "merged into <task>", or deletion if it carried nothing unique).
+- *Parent with children* — when the members are related but distinct (each ships independently or has its own value), promote a parent task and re-home the members beneath it as sub-tasks, so the list shows the effort as a unit without losing the individual pieces.
+
+Never merge or re-parent autonomously — which tasks belong together, and whether they're one-work or related-distinct, is a judgment only Craig ratifies. Propose, don't apply, until he picks. A cluster he declines stays as separate tasks; don't re-surface it every audit (note the decline in the session log).
+
+When no clear cluster exists, say so in one line and move on — most audits won't find one, and forcing a merge fragments worse than it consolidates.
+
** Phase D — Flag the judgment calls (interactive)
Present the NEEDS-USER bucket as a short, scannable list — one line per task, naming the decision or the fact required. Adjudicate with the user one item at a time (inline numbered options per =interaction.md=, no popup). Apply the user's calls as they come (which may itself produce more autonomous updates, or new tasks).