aboutsummaryrefslogtreecommitdiff
path: root/.ai/scripts
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-31 00:07:03 -0500
committerCraig Jennings <c@cjennings.net>2026-05-31 00:07:03 -0500
commit8c0eca8375db2c2d346f5fd08ac752209349f94e (patch)
treed62abf74ad991ca54f1dcdcc1b3f225c4e8633a1 /.ai/scripts
parentddcde66a768758844a5be705de6a89e68697fa1a (diff)
downloadrulesets-8c0eca8375db2c2d346f5fd08ac752209349f94e.tar.gz
rulesets-8c0eca8375db2c2d346f5fd08ac752209349f94e.zip
feat(workflows): add monitor-inbox workflow + inbox-status script
Handoffs that arrive mid-session used to sit unseen until the next startup or a manual check. Today's burst of cross-project handoffs made that gap obvious. I added monitor-inbox.org, the cadence-and-decision layer over process-inbox: check the inbox at every task boundary, decide act-now (just do it) versus file (ask, with filing as option 1), and reply to the sender. An opt-in background-monitor /loop recipe covers unattended watching. inbox-status (with bats tests) is the cheap check the cadence calls. It lists unprocessed handoffs and exits nonzero when any are pending, using the same artifact exclusions as the wrap-up sanity check. protocols.org gets a short cadence note so the habit fires every session, and INDEX.org lists the new workflow. The act-vs-file rule (act-now is silent, filing asks with file as option 1, ambiguity asks) is the decision protocol we settled today.
Diffstat (limited to '.ai/scripts')
-rwxr-xr-x.ai/scripts/inbox-status50
-rw-r--r--.ai/scripts/tests/inbox-status.bats56
2 files changed, 106 insertions, 0 deletions
diff --git a/.ai/scripts/inbox-status b/.ai/scripts/inbox-status
new file mode 100755
index 0000000..b917144
--- /dev/null
+++ b/.ai/scripts/inbox-status
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+# inbox-status — list unprocessed inbox handoffs; exit nonzero if any are pending.
+#
+# "Unprocessed" = a regular file in inbox/ that isn't a pipeline artifact. The
+# exclusions match the wrap-up inbox sanity check: .gitkeep, lint-followups.org
+# (the lint-org pipeline file daily-prep consumes), and any PROCESSED-* file
+# (explicitly deferred).
+#
+# Prints one indented line per pending handoff, then a summary count.
+#
+# Exit codes (so a cadence check can gate cheaply — `inbox-status -q || ...`):
+# 0 inbox clean (only artifacts)
+# 1 one or more handoffs pending
+# 2 no inbox/ directory, or bad usage
+#
+# Flags:
+# -q / --quiet print only the summary count line, not the per-item lines
+#
+# Run from a project root (where inbox/ lives).
+set -euo pipefail
+
+quiet=0
+case "${1:-}" in
+ -q|--quiet) quiet=1 ;;
+ "") ;;
+ *) echo "usage: inbox-status [-q|--quiet]" >&2; exit 2 ;;
+esac
+
+if [ ! -d inbox ]; then
+ echo "inbox-status: no inbox/ directory" >&2
+ exit 2
+fi
+
+mapfile -t pending < <(find inbox -maxdepth 1 -type f \
+ ! -name '.gitkeep' \
+ ! -name 'lint-followups.org' \
+ ! -name 'PROCESSED-*' \
+ -printf '%f\n' 2>/dev/null | sort)
+
+n=${#pending[@]}
+
+if [ "$quiet" -eq 0 ]; then
+ for f in "${pending[@]}"; do
+ printf ' %s\n' "$f"
+ done
+fi
+printf 'inbox-status: %d pending handoff(s)\n' "$n"
+
+[ "$n" -gt 0 ] && exit 1
+exit 0
diff --git a/.ai/scripts/tests/inbox-status.bats b/.ai/scripts/tests/inbox-status.bats
new file mode 100644
index 0000000..bc8a734
--- /dev/null
+++ b/.ai/scripts/tests/inbox-status.bats
@@ -0,0 +1,56 @@
+#!/usr/bin/env bats
+# Tests for inbox-status: list unprocessed inbox handoffs, exit nonzero if any.
+
+setup() {
+ SCRIPT="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)/inbox-status"
+ TMP="$(mktemp -d)"
+}
+
+teardown() {
+ rm -rf "$TMP"
+}
+
+@test "inbox-status: no inbox/ dir exits 2" {
+ cd "$TMP"
+ run "$SCRIPT"
+ [ "$status" -eq 2 ]
+}
+
+@test "inbox-status: only .gitkeep is clean (exit 0)" {
+ mkdir "$TMP/inbox"
+ touch "$TMP/inbox/.gitkeep"
+ cd "$TMP"
+ run "$SCRIPT"
+ [ "$status" -eq 0 ]
+ [[ "$output" == *"0 pending"* ]]
+}
+
+@test "inbox-status: a handoff is pending (exit 1, listed)" {
+ mkdir "$TMP/inbox"
+ touch "$TMP/inbox/.gitkeep"
+ echo body > "$TMP/inbox/2026-05-31-from-work-thing.org"
+ cd "$TMP"
+ run "$SCRIPT"
+ [ "$status" -eq 1 ]
+ [[ "$output" == *"1 pending"* ]]
+ [[ "$output" == *"2026-05-31-from-work-thing.org"* ]]
+}
+
+@test "inbox-status: excludes lint-followups.org and PROCESSED-* artifacts" {
+ mkdir "$TMP/inbox"
+ touch "$TMP/inbox/.gitkeep" "$TMP/inbox/lint-followups.org" "$TMP/inbox/PROCESSED-old.org"
+ cd "$TMP"
+ run "$SCRIPT"
+ [ "$status" -eq 0 ]
+ [[ "$output" == *"0 pending"* ]]
+}
+
+@test "inbox-status: -q suppresses the per-item lines" {
+ mkdir "$TMP/inbox"
+ echo body > "$TMP/inbox/handoff.org"
+ cd "$TMP"
+ run "$SCRIPT" -q
+ [ "$status" -eq 1 ]
+ [[ "$output" == *"1 pending"* ]]
+ [[ "$output" != *" handoff.org"* ]]
+}