aboutsummaryrefslogtreecommitdiff
path: root/.ai/scripts/cross-agent-comms/cross-agent-watch.md
blob: dd8afc147e8dca86c5a035adf47b7cdc82218891 (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
# 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>"`.
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.