aboutsummaryrefslogtreecommitdiff
path: root/.ai/scripts/cross-agent-comms/cross-agent-watch.md
blob: 04e80053e2a558fab4c9bee68fee32ec6e90260c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# cross-agent-watch

**Purpose.** Long-running watcher that fires desktop notifications when new
cross-agent messages land in any project's `inbox/from-agents/` directory.
This is the primary cold-start mechanism: messages get noticed even when no
Claude session is active.

## Usage

```
cross-agent-watch [--projects-glob <glob>] [--log <path>]
```

No args required. Defaults:

- Watches `~/projects/*/inbox/from-agents/` (matches every project with the
  cross-agent-comms convention).
- Logs each event to `~/.local/state/cross-agent-comms/watch.log`.

### Flags

| Flag | Default | Purpose |
|---|---|---|
| `--projects-glob <glob>` | `~/projects/*/inbox/from-agents/` | Override which directories to watch. Useful for testing on a single project. |
| `--log <path>` | `~/.local/state/cross-agent-comms/watch.log` | Override log location. Set to `/dev/null` to disable logging. |
| `--quiet` | off | Suppress stdout output. Notifications still fire. |
| `--no-notify` | off | Skip `notify` calls. Useful for testing the watcher loop without spamming notifications. |

## Behavior

1. Resolves the projects-glob to a concrete list of directories at startup.
   New projects added to `~/projects/` after startup are NOT picked up — restart
   the watcher to re-resolve.
2. Runs `inotifywait -m -e create,moved_to --format '%w%f'` against each
   watched directory.
3. For each event, calls
   `notify info "Cross-agent message" "<project>: <filename>" --persist`. The
   `--persist` flag keeps the page on screen until dismissed, so an inbound
   message that arrives while Craig is away from the desk isn't missed.
4. Appends an event line to the log:
   `<ISO-8601-timestamp>\t<project>\t<filename>`.

## Event filtering

- Watches `create` AND `moved_to` events. The `moved_to` part is critical for
  the atomic-write convention (`mktemp` + `mv` produces a `moved_to`, not a
  `create`).
- Files starting with `.tmp.` are ignored — they're staging files from
  in-progress writes that should never produce a notification.

## Installation

### Option A — tmux pane (personal, easy)

Run in a tmux pane that survives session disconnects:

```
tmux new -d -s cross-agent-watch 'cross-agent-watch'
```

### Option B — systemd user service (production)

Provided files:

- `~/.config/systemd/user/cross-agent-watch.service`
- `~/.config/systemd/user/cross-agent-watch.path`

Enable with:

```
systemctl --user enable --now cross-agent-watch.path
```

The path unit triggers the service unit on filesystem changes; the service
unit re-execs `cross-agent-watch` if it dies. Survives reboot.

## Failure modes

| Symptom | Likely cause | Fix |
|---|---|---|
| No notifications fire on new files | inotifywait not running, or glob resolved to zero dirs | Check `cross-agent-watch --projects-glob ... --quiet` exits non-zero immediately. Log shows `"resolved 0 directories"`. |
| Notifications fire on `.tmp.` files | Filter regression | Verify `inotifywait` events show the `.tmp.` files; if so check this script's filter logic. |
| Some files missed under rapid bursts | inotify queue overflow | Increase `fs.inotify.max_queued_events` sysctl. Default 16384 is usually fine. |
| Permission denied on a watched dir | Directory perms wrong | `chmod 700 <dir>` and confirm owner. |

## HALT awareness

Checks `~/.config/cross-agent-comms/HALT` on each iteration (each inotifywait
event fired). If HALT exists, the watcher continues running but **suppresses
the `notify` call**. The event is still logged, with `(suppressed by HALT)`
appended:

```
2026-04-27T04:42:00-05:00	career	20260427T094200Z-from-homelab-test.org	(suppressed by HALT)
```

Logged-but-suppressed events are useful for the operator to see what would
have fired during the halt window — helpful for diagnosing whatever caused
the halt.

When HALT clears, suppression stops; subsequent events fire normally. Backlog
events that arrived during halt are NOT replayed — they get picked up via
cold-start handling (status CLI, agent startup check, or the next agent
poll once polling resumes).

If the HALT file exists but is unreadable, fail-closed (suppress) — safer
than fail-open.

See `cross-agent-halt.md` for the full halt mechanism.

## Examples

```bash
# Watch all projects, log everything, fire notifications
cross-agent-watch

# Test against a single project, no notifications, verbose
cross-agent-watch \
  --projects-glob "$HOME/projects/work/inbox/from-agents/" \
  --no-notify

# Production-style: quiet stdout, log only
cross-agent-watch --quiet
```

## See also

- `cross-agent-status` — point-in-time snapshot of pending messages.
- `cross-agent-send` — counterpart writer.
- `cross-agent-comms.org` — protocol spec.