aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-12 15:26:22 -0500
committerCraig Jennings <c@cjennings.net>2026-06-12 15:26:22 -0500
commit13256aad033f84c0854f2d562685ea808a5ec619 (patch)
treebe030ced846ce87eabd9f8c18dac5e221b0611d3
parent21ab10ef9e2fff9b4726695036e95e33937e1fa9 (diff)
downloadrulesets-13256aad033f84c0854f2d562685ea808a5ec619.tar.gz
rulesets-13256aad033f84c0854f2d562685ea808a5ec619.zip
chore: delete the page-signal pager wrapper
Remove the page-signal CLI wrapper, its workflow, and the references in INDEX.org, broadcast.org, and mcp/README.org. The signal MCP server stays. It's the two-way path and a separate capability. The pager number had deregistered and the send-only wrapper isn't worth re-registering.
-rw-r--r--.ai/workflows/INDEX.org2
-rw-r--r--.ai/workflows/broadcast.org2
-rw-r--r--.ai/workflows/page-signal.org87
-rw-r--r--claude-templates/.ai/workflows/INDEX.org2
-rw-r--r--claude-templates/.ai/workflows/broadcast.org2
-rw-r--r--claude-templates/.ai/workflows/page-signal.org87
-rwxr-xr-xclaude-templates/bin/page-signal130
-rw-r--r--mcp/README.org2
8 files changed, 3 insertions, 311 deletions
diff --git a/.ai/workflows/INDEX.org b/.ai/workflows/INDEX.org
index a910230..47ad844 100644
--- a/.ai/workflows/INDEX.org
+++ b/.ai/workflows/INDEX.org
@@ -87,8 +87,6 @@ This index must list every =.org= file in =.ai/workflows/= except this one and e
- =process-meeting-transcript.org= — record → transcript → labeled archive.
- Triggers: "process the transcript", "process the recording". Auto: new files in =~/sync/recordings/=.
-- =page-signal.org= — send Craig a Signal message via =page-signal= when desktop notifications won't reach him. Defaults to note-to-self. Outbound to other contacts requires explicit =--to <+number>= every call. Auto: long-running task completion, cross-device deliverables, operator-attention events. NOT for routine completions or periodic status pings.
- - Triggers: "page me on signal", "signal me when X is done", "send a signal note about X"
- =broadcast.org= — fan out a single message to every AI project's inbox via the discovery helper =broadcast.py= + the existing =inbox-send.py=. Two modes: *announcement* (a tooling / capability / rule change every agent should know) and *situational* (a life or work event — travel, a visitor, quitting a job — said once so every project's agent holds the context and applies it on its own judgment). Use sparingly; not for project-specific handoffs.
- Announcement triggers: "broadcast this to every project", "notify every project about X", "fan out this announcement", "let every project know X is available"
- Situational triggers: "broadcast the <event> to all projects", "broadcast that <situation>", "let every project know I'll be away ..."
diff --git a/.ai/workflows/broadcast.org b/.ai/workflows/broadcast.org
index 0d3d1c0..1be07d2 100644
--- a/.ai/workflows/broadcast.org
+++ b/.ai/workflows/broadcast.org
@@ -22,7 +22,7 @@ The mode picks the message template (Compose) and the receiving contract. Everyt
- "let every project know X is available"
Automatic announcement triggers:
-- *New machine-global capability landed.* A new script in =~/.local/bin/=, a new MCP server, a new tool (e.g. =signal-cli=, =page-signal=). Projects need to know it's available.
+- *New machine-global capability landed.* A new script in =~/.local/bin/=, a new MCP server, a new tool (e.g. =signal-cli=). Projects need to know it's available.
- *Shared rule or protocol change* in =claude-rules/= or =claude-templates/.ai/= that materially changes how every project's agent should behave.
- *Deprecation notice* — a script, workflow, or rule going away; give every project a chance to migrate.
diff --git a/.ai/workflows/page-signal.org b/.ai/workflows/page-signal.org
deleted file mode 100644
index e5d192f..0000000
--- a/.ai/workflows/page-signal.org
+++ /dev/null
@@ -1,87 +0,0 @@
-#+TITLE: Page Signal Workflow
-#+AUTHOR: Craig Jennings & Claude
-#+DATE: 2026-05-29
-
-* Overview
-
-Send Craig a Signal message via =page-signal= when desktop notifications won't reach him. Signal fires cross-device, so a page arrives on his phone even when he's away from the desk. The wrapper lives at =~/.local/bin/page-signal= (rulesets-installed; symlinked from =claude-templates/bin/page-signal=).
-
-Pages Craig's Signal account by default, sent from a dedicated pager account. Override the recipient with =--to <+number-or-uuid>=. The sender account and default recipient come from =PAGE_SIGNAL_ACCOUNT= and =PAGE_SIGNAL_TO=, both with built-in defaults baked into the wrapper.
-
-*Notification routing (resolved 2026-06-02):* =signal-cli= is registered with a dedicated Google Voice number (profile "Claude Pager"), separate from Craig's primary Signal account. A page travels from that account to Craig's Signal account, so it arrives as a normal incoming message from a third party and fires a mobile push notification. The earlier limitation — a primary-number account messaging itself, which Signal mobile won't notify on — no longer applies now that the sender is a distinct account. The literal sender number and default recipient (Craig's Signal account UUID) live in =page-signal= and =mcp/servers.json=.
-
-* When to Use This Workflow
-
-User triggers (rare; this is usually invoked by other workflows or by Claude autonomously per the rules below):
-
-- "page me on signal" / "signal me when X is done"
-- "send a signal note about <thing>"
-
-Automatic invocation:
-
-- *Long-running task completion* — when a task estimated >10 min finishes successfully or fails, fire =page-signal= in addition to =notify= so Craig sees it on his phone if he's away.
-- *Cross-device deliverables* — when generating a file or screenshot Craig will want on his phone (a quick reference, a meeting prep summary, etc.), attach via =page-signal --file=.
-- *Operator-attention events* — when an autonomous run needs Craig's eyes and the desktop notify might miss him.
-
-* When NOT to Use This Workflow
-
-- *Routine completions.* The desktop =notify success= covers everything that finishes within a normal session. Signal pages should be the exception, not the default.
-- *Periodic status pings.* Long-running-process status updates (per =protocols.org='s 5-minute cadence) go to desktop only. Signal-paging every five minutes is spam.
-- *Trivial confirmations.* "Commit landed", "test passed", "file saved" don't earn a Signal page.
-- *Outbound to other contacts without explicit instruction.* =--to <+number>= is per-message, not a saved address book. Each outbound page needs Craig's explicit instruction naming the recipient.
-
-* Mechanics
-
-** Direct invocation
-
-#+begin_src bash
-# Note-to-self (default):
-page-signal "Build finished. 12 min, all tests green."
-
-# With attachment:
-page-signal --file /tmp/report.pdf "Daily prep ready."
-
-# Outbound (explicit recipient):
-page-signal --to +15551234567 "Running 10 minutes late."
-
-# Quiet mode (suppress stdout success line):
-page-signal --quiet "Done."
-
-# JSON output (for scripted callers):
-page-signal --json "Done."
-#+end_src
-
-Exit codes:
-- =0= — sent successfully
-- =1= — signal-cli reported a send failure (network, rate limit, recipient unreachable)
-- =2= — usage error (missing arg, invalid =--to= format)
-- =3= — =signal-cli= not installed
-
-** Composition with =notify=
-
-If the =notify= script gains a =--signal= flag (currently a separate handoff to the dotfiles project), it can fire desktop notification + Signal page in one call. Until then, run both:
-
-#+begin_src bash
-notify success "Build done" "12 min, all green" --persist
-page-signal "Build done — 12 min, all green."
-#+end_src
-
-* Safety Rails
-
-1. *No outbound without explicit instruction per send.* The Signal protocol doesn't distinguish between "Craig asked me to text Alice" and "I decided Alice should hear from me." The latter is never appropriate. Every =--to <+number>= invocation must trace back to a Craig directive that names the recipient.
-2. *No saved address book.* Don't memoize contact numbers in scripts or workflows. The explicit =+number= per call is the rate limiter on accidental sends.
-3. *Rate limit awareness.* Signal rate-limits high-volume sends. If a session is firing >5 pages in a few minutes, that's a smell — consolidate into one summary page.
-4. *Sensitive content.* Signal is end-to-end encrypted to Craig's devices, but the message body is visible on every device he's logged in on (phone, desktop, web). Don't page secrets, credentials, or anything you wouldn't want shoulder-surfed.
-5. *Failure semantics.* A page that didn't land is the failure mode you'll never notice. The wrapper returns non-zero on send failure — callers that depend on delivery should check the exit code, not assume.
-
-* Common Mistakes
-
-1. *Signal-paging every notify call.* Defeats the purpose. Signal is the exception for cross-device pages.
-2. *Using =--to= with a stored number.* Each outbound needs Craig's instruction. No defaults.
-3. *Paging during automated periodic checks.* Use desktop notify for periodic status. Signal is for events Craig wants to react to.
-4. *Sending the full task body via Signal.* One sentence, not a wall of text. Signal pages are glanceable; long messages buried on a phone get skimmed past.
-5. *Ignoring exit code 1.* The page didn't arrive. Either retry or surface the failure to Craig at the next interactive moment.
-
-* Living Document
-
-Tune the "automatic invocation" criteria as the cadence shapes up. If certain long-running task classes consistently warrant Signal pages and others don't, fold the pattern into the heuristic. If a =notify --signal= flag lands in the dotfiles, update the composition section.
diff --git a/claude-templates/.ai/workflows/INDEX.org b/claude-templates/.ai/workflows/INDEX.org
index a910230..47ad844 100644
--- a/claude-templates/.ai/workflows/INDEX.org
+++ b/claude-templates/.ai/workflows/INDEX.org
@@ -87,8 +87,6 @@ This index must list every =.org= file in =.ai/workflows/= except this one and e
- =process-meeting-transcript.org= — record → transcript → labeled archive.
- Triggers: "process the transcript", "process the recording". Auto: new files in =~/sync/recordings/=.
-- =page-signal.org= — send Craig a Signal message via =page-signal= when desktop notifications won't reach him. Defaults to note-to-self. Outbound to other contacts requires explicit =--to <+number>= every call. Auto: long-running task completion, cross-device deliverables, operator-attention events. NOT for routine completions or periodic status pings.
- - Triggers: "page me on signal", "signal me when X is done", "send a signal note about X"
- =broadcast.org= — fan out a single message to every AI project's inbox via the discovery helper =broadcast.py= + the existing =inbox-send.py=. Two modes: *announcement* (a tooling / capability / rule change every agent should know) and *situational* (a life or work event — travel, a visitor, quitting a job — said once so every project's agent holds the context and applies it on its own judgment). Use sparingly; not for project-specific handoffs.
- Announcement triggers: "broadcast this to every project", "notify every project about X", "fan out this announcement", "let every project know X is available"
- Situational triggers: "broadcast the <event> to all projects", "broadcast that <situation>", "let every project know I'll be away ..."
diff --git a/claude-templates/.ai/workflows/broadcast.org b/claude-templates/.ai/workflows/broadcast.org
index 0d3d1c0..1be07d2 100644
--- a/claude-templates/.ai/workflows/broadcast.org
+++ b/claude-templates/.ai/workflows/broadcast.org
@@ -22,7 +22,7 @@ The mode picks the message template (Compose) and the receiving contract. Everyt
- "let every project know X is available"
Automatic announcement triggers:
-- *New machine-global capability landed.* A new script in =~/.local/bin/=, a new MCP server, a new tool (e.g. =signal-cli=, =page-signal=). Projects need to know it's available.
+- *New machine-global capability landed.* A new script in =~/.local/bin/=, a new MCP server, a new tool (e.g. =signal-cli=). Projects need to know it's available.
- *Shared rule or protocol change* in =claude-rules/= or =claude-templates/.ai/= that materially changes how every project's agent should behave.
- *Deprecation notice* — a script, workflow, or rule going away; give every project a chance to migrate.
diff --git a/claude-templates/.ai/workflows/page-signal.org b/claude-templates/.ai/workflows/page-signal.org
deleted file mode 100644
index e5d192f..0000000
--- a/claude-templates/.ai/workflows/page-signal.org
+++ /dev/null
@@ -1,87 +0,0 @@
-#+TITLE: Page Signal Workflow
-#+AUTHOR: Craig Jennings & Claude
-#+DATE: 2026-05-29
-
-* Overview
-
-Send Craig a Signal message via =page-signal= when desktop notifications won't reach him. Signal fires cross-device, so a page arrives on his phone even when he's away from the desk. The wrapper lives at =~/.local/bin/page-signal= (rulesets-installed; symlinked from =claude-templates/bin/page-signal=).
-
-Pages Craig's Signal account by default, sent from a dedicated pager account. Override the recipient with =--to <+number-or-uuid>=. The sender account and default recipient come from =PAGE_SIGNAL_ACCOUNT= and =PAGE_SIGNAL_TO=, both with built-in defaults baked into the wrapper.
-
-*Notification routing (resolved 2026-06-02):* =signal-cli= is registered with a dedicated Google Voice number (profile "Claude Pager"), separate from Craig's primary Signal account. A page travels from that account to Craig's Signal account, so it arrives as a normal incoming message from a third party and fires a mobile push notification. The earlier limitation — a primary-number account messaging itself, which Signal mobile won't notify on — no longer applies now that the sender is a distinct account. The literal sender number and default recipient (Craig's Signal account UUID) live in =page-signal= and =mcp/servers.json=.
-
-* When to Use This Workflow
-
-User triggers (rare; this is usually invoked by other workflows or by Claude autonomously per the rules below):
-
-- "page me on signal" / "signal me when X is done"
-- "send a signal note about <thing>"
-
-Automatic invocation:
-
-- *Long-running task completion* — when a task estimated >10 min finishes successfully or fails, fire =page-signal= in addition to =notify= so Craig sees it on his phone if he's away.
-- *Cross-device deliverables* — when generating a file or screenshot Craig will want on his phone (a quick reference, a meeting prep summary, etc.), attach via =page-signal --file=.
-- *Operator-attention events* — when an autonomous run needs Craig's eyes and the desktop notify might miss him.
-
-* When NOT to Use This Workflow
-
-- *Routine completions.* The desktop =notify success= covers everything that finishes within a normal session. Signal pages should be the exception, not the default.
-- *Periodic status pings.* Long-running-process status updates (per =protocols.org='s 5-minute cadence) go to desktop only. Signal-paging every five minutes is spam.
-- *Trivial confirmations.* "Commit landed", "test passed", "file saved" don't earn a Signal page.
-- *Outbound to other contacts without explicit instruction.* =--to <+number>= is per-message, not a saved address book. Each outbound page needs Craig's explicit instruction naming the recipient.
-
-* Mechanics
-
-** Direct invocation
-
-#+begin_src bash
-# Note-to-self (default):
-page-signal "Build finished. 12 min, all tests green."
-
-# With attachment:
-page-signal --file /tmp/report.pdf "Daily prep ready."
-
-# Outbound (explicit recipient):
-page-signal --to +15551234567 "Running 10 minutes late."
-
-# Quiet mode (suppress stdout success line):
-page-signal --quiet "Done."
-
-# JSON output (for scripted callers):
-page-signal --json "Done."
-#+end_src
-
-Exit codes:
-- =0= — sent successfully
-- =1= — signal-cli reported a send failure (network, rate limit, recipient unreachable)
-- =2= — usage error (missing arg, invalid =--to= format)
-- =3= — =signal-cli= not installed
-
-** Composition with =notify=
-
-If the =notify= script gains a =--signal= flag (currently a separate handoff to the dotfiles project), it can fire desktop notification + Signal page in one call. Until then, run both:
-
-#+begin_src bash
-notify success "Build done" "12 min, all green" --persist
-page-signal "Build done — 12 min, all green."
-#+end_src
-
-* Safety Rails
-
-1. *No outbound without explicit instruction per send.* The Signal protocol doesn't distinguish between "Craig asked me to text Alice" and "I decided Alice should hear from me." The latter is never appropriate. Every =--to <+number>= invocation must trace back to a Craig directive that names the recipient.
-2. *No saved address book.* Don't memoize contact numbers in scripts or workflows. The explicit =+number= per call is the rate limiter on accidental sends.
-3. *Rate limit awareness.* Signal rate-limits high-volume sends. If a session is firing >5 pages in a few minutes, that's a smell — consolidate into one summary page.
-4. *Sensitive content.* Signal is end-to-end encrypted to Craig's devices, but the message body is visible on every device he's logged in on (phone, desktop, web). Don't page secrets, credentials, or anything you wouldn't want shoulder-surfed.
-5. *Failure semantics.* A page that didn't land is the failure mode you'll never notice. The wrapper returns non-zero on send failure — callers that depend on delivery should check the exit code, not assume.
-
-* Common Mistakes
-
-1. *Signal-paging every notify call.* Defeats the purpose. Signal is the exception for cross-device pages.
-2. *Using =--to= with a stored number.* Each outbound needs Craig's instruction. No defaults.
-3. *Paging during automated periodic checks.* Use desktop notify for periodic status. Signal is for events Craig wants to react to.
-4. *Sending the full task body via Signal.* One sentence, not a wall of text. Signal pages are glanceable; long messages buried on a phone get skimmed past.
-5. *Ignoring exit code 1.* The page didn't arrive. Either retry or surface the failure to Craig at the next interactive moment.
-
-* Living Document
-
-Tune the "automatic invocation" criteria as the cadence shapes up. If certain long-running task classes consistently warrant Signal pages and others don't, fold the pattern into the heuristic. If a =notify --signal= flag lands in the dotfiles, update the composition section.
diff --git a/claude-templates/bin/page-signal b/claude-templates/bin/page-signal
deleted file mode 100755
index ef64258..0000000
--- a/claude-templates/bin/page-signal
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env bash
-#
-# page-signal — wrap signal-cli send for paging Craig via Signal.
-#
-# Sends from a dedicated pager account to Craig's Signal account by
-# default. Override the recipient with --to <+number-or-uuid>.
-#
-# Usage:
-# page-signal "message" # page Craig (default recipient)
-# page-signal --file path "message" # with attachment
-# page-signal --to +15551234567 "msg" # override recipient (number or UUID)
-# page-signal --quiet "message" # suppress success output
-# page-signal --json "message" # structured output (timestamp + status)
-# echo "msg" | page-signal # message from stdin (no positional)
-#
-# Sender account and default recipient come from PAGE_SIGNAL_ACCOUNT and
-# PAGE_SIGNAL_TO; both have built-in defaults below. Requires signal-cli
-# installed and registered with the sender account.
-#
-# Use this when desktop notifications won't reach the user — page-signal
-# fires cross-device. For routine completions and periodic status pings,
-# stick with `notify`; Signal is for things that need attention while away
-# from the desk.
-
-set -euo pipefail
-
-quiet=0
-json=0
-file=
-account="${PAGE_SIGNAL_ACCOUNT:-+15045173983}"
-recipient_args=("${PAGE_SIGNAL_TO:-b1b5601e-6126-47f8-afaa-0a59f5188fde}")
-message=
-
-usage() {
- sed -n '3,23p' "$0" | sed 's/^# \{0,1\}//'
-}
-
-while [ "$#" -gt 0 ]; do
- case "$1" in
- -h|--help)
- usage
- exit 0
- ;;
- --quiet)
- quiet=1
- shift
- ;;
- --json)
- json=1
- shift
- ;;
- --file)
- [ "$#" -ge 2 ] || { echo "page-signal: --file needs a path" >&2; exit 2; }
- file="$2"
- [ -f "$file" ] || { echo "page-signal: file not found: $file" >&2; exit 2; }
- shift 2
- ;;
- --to)
- [ "$#" -ge 2 ] || { echo "page-signal: --to needs a +E.164 number or a Signal account UUID" >&2; exit 2; }
- case "$2" in
- +[0-9]*) ;;
- [0-9a-fA-F]*-[0-9a-fA-F]*-[0-9a-fA-F]*) ;;
- *) echo "page-signal: --to expects +E.164 (e.g. +15551234567) or a Signal account UUID" >&2; exit 2 ;;
- esac
- recipient_args=("$2")
- shift 2
- ;;
- --)
- shift
- break
- ;;
- -*)
- echo "page-signal: unknown flag: $1 (use --help)" >&2
- exit 2
- ;;
- *)
- message="$1"
- shift
- ;;
- esac
-done
-
-if ! command -v signal-cli >/dev/null 2>&1; then
- echo "page-signal: signal-cli not found in PATH" >&2
- exit 3
-fi
-
-# Message: from positional arg, or from stdin if none given.
-if [ -z "$message" ]; then
- if [ -t 0 ]; then
- echo "page-signal: no message (pass as arg or pipe via stdin)" >&2
- exit 2
- fi
- message="$(cat)"
-fi
-
-# Build the send command.
-cmd=(signal-cli -a "$account" send -m "$message")
-if [ -n "$file" ]; then
- cmd+=(-a "$file")
-fi
-cmd+=("${recipient_args[@]}")
-
-# Send. Capture stderr so we can surface clean failure messages.
-timestamp="$(date '+%Y-%m-%dT%H:%M:%S%z')"
-if err="$("${cmd[@]}" 2>&1 >/dev/null)"; then
- status=ok
-else
- status=fail
-fi
-
-if [ "$json" -eq 1 ]; then
- printf '{"status":"%s","timestamp":"%s","recipient":"%s"' \
- "$status" "$timestamp" "${recipient_args[0]}"
- if [ -n "$file" ]; then
- printf ',"attachment":"%s"' "$file"
- fi
- if [ "$status" = "fail" ]; then
- printf ',"error":"%s"' "$(echo "$err" | head -1 | sed 's/"/\\"/g')"
- fi
- printf '}\n'
-elif [ "$quiet" -eq 0 ]; then
- if [ "$status" = "ok" ]; then
- echo "page-signal: sent to ${recipient_args[*]} at $timestamp"
- else
- echo "page-signal: FAIL — $err" >&2
- fi
-fi
-
-[ "$status" = "ok" ]
diff --git a/mcp/README.org b/mcp/README.org
index 30dc082..ac65ffd 100644
--- a/mcp/README.org
+++ b/mcp/README.org
@@ -90,4 +90,4 @@ Prerequisites on a fresh machine, in order:
2. Register the dedicated pager account. Signal requires a captcha for registration: run =signal-cli -a +<number> register=, follow the printed =signalcaptchas.org= link, solve it, and pass the resulting token to =signal-cli -a +<number> register --captcha <token>= within a minute or two before it expires. Signal then texts a code to the number; verify with =signal-cli -a +<number> verify <code>=.
3. =make install-mcp= registers =signal-mcp= pointed at that =--user-id=.
-The =--user-id= is a *dedicated* number (a Google Voice number registered to =signal-cli=), not Craig's primary. Signal mobile won't push-notify a message an account sends to itself, so paging from the primary to itself is silent; a distinct sender account reaching Craig's account notifies normally. Craig's account hides its phone number under phone-number privacy, so the destination is its stable account UUID rather than a number. The same account and recipient back the =page-signal= CLI wrapper (=PAGE_SIGNAL_ACCOUNT= / =PAGE_SIGNAL_TO=). The MCP server is the two-way path (=receive_message= to listen for replies); =page-signal= is the fast send-only path.
+The =--user-id= is a *dedicated* number (a Google Voice number registered to =signal-cli=), not Craig's primary. Signal mobile won't push-notify a message an account sends to itself, so paging from the primary to itself is silent; a distinct sender account reaching Craig's account notifies normally. Craig's account hides its phone number under phone-number privacy, so the destination is its stable account UUID rather than a number. The MCP server is the two-way path (=receive_message= to listen for replies).