Environment
- OS: Windows 11
- Shell: Git Bash (MINGW64)
- agmsg: v1.1.0 (installed via
npm i -g agmsg → agmsg install)
- sqlite: native Windows
sqlite3.exe on PATH
Found while running several Claude Code agents coordinated through agmsg on Windows. One primary bug plus four related findings. Happy to PR the first one (or two).
① [BUG] native sqlite3.exe cannot open the MSYS /c/... DB path → inbox/send/watch fail (primary, easy fix)
agmsg_db_path() (in scripts/lib/storage.sh) returns an MSYS/Git Bash path like /c/Users/<you>/.agents/skills/agmsg/db/messages.db. The native Windows sqlite3.exe cannot open that form — it fails with unable to open database file (CANTOPEN). Because every DB call site goes through DB="$(agmsg_db_path)", this takes down inbox.sh, send.sh, watch.sh, task-*, etc. at once.
It reproduces reliably when the environment has MSYS2_ARG_CONV_EXCL=* (MSYS path conversion suppressed, so the /c/ form reaches sqlite unchanged). watch.sh keeps running even when it can't open the DB, so this presents as a silent failure that's hard to diagnose.
Fix (small, low-risk): add a cygpath -m conversion in agmsg_db_path(), mirroring the existing cygpath -w handling in agmsg_sql_readfile_path in the same file. -m yields the C:/Users/... mixed (forward-slash) form, which both Git Bash [ -f ] tests and sqlite3.exe accept. No-op off Windows:
agmsg_db_path() {
local p
p="$(agmsg_storage_dir)/messages.db"
if command -v cygpath >/dev/null 2>&1; then
p="$(cygpath -m "$p" 2>/dev/null || printf '%s' "$p")"
fi
printf '%s\n' "$p"
}
Since agmsg_db_path is the single chokepoint, this one change fixes every DB-backed script. I can open a PR for this.
② [BUG] watch.sh survives a DB-open failure silently
When the DB can't be opened (see ①), watch.sh keeps running and emits nothing, so the operator can't tell receiving is dead. Suggestion: a sqlite3 "$DB" 'SELECT 1;' health check at startup (and/or periodically) that prints a single ERROR: cannot open message DB <path> line to stdout on failure.
③ [FEATURE] catch-up drain of unread inbox on watcher attach
The monitor (watch.sh) streams only messages that arrive after attach. A message queued before the watcher attaches is missed — e.g. spawning a worker and immediately sending it a task: the worker reports READY but never sees/acts on the queued task, so orchestration has to wait for READY and then send live. Suggestion: on attach, drain & emit unread inbox once before entering the live stream.
④ [BUG] despawn ineffective for non-tmux (OS-terminal) spawns on Windows
spawn via an OS terminal / AGMSG_TERMINAL template does not write a placement record, so despawn --force exits with no placement record and does nothing; graceful despawn is also a no-op when no live actas lock is held. The result is that a spawned member can only be removed with leave.sh (de-register) plus manually closing the window. Suggestion: record placement (or at least launch metadata) for OS-terminal spawns so despawn can de-register consistently.
⑤ [FEATURE] length guard in send.sh
Long bodies sent over agmsg clutter the recipient inbox / terminal. Suggestion: a max-length guard in send.sh (e.g. warn + refuse over ~2KB, nudging toward a file reference) for the "short notification + payload in a file" pattern.
Thanks for agmsg — the daemonless SQLite design works well; these are all Windows/Git-Bash edges. ① in particular is a small change with a big payoff on Windows.
Environment
npm i -g agmsg→agmsg install)sqlite3.exeon PATHFound while running several Claude Code agents coordinated through agmsg on Windows. One primary bug plus four related findings. Happy to PR the first one (or two).
① [BUG] native
sqlite3.execannot open the MSYS/c/...DB path → inbox/send/watch fail (primary, easy fix)agmsg_db_path()(inscripts/lib/storage.sh) returns an MSYS/Git Bash path like/c/Users/<you>/.agents/skills/agmsg/db/messages.db. The native Windowssqlite3.execannot open that form — it fails withunable to open database file(CANTOPEN). Because every DB call site goes throughDB="$(agmsg_db_path)", this takes downinbox.sh,send.sh,watch.sh,task-*, etc. at once.It reproduces reliably when the environment has
MSYS2_ARG_CONV_EXCL=*(MSYS path conversion suppressed, so the/c/form reaches sqlite unchanged).watch.shkeeps running even when it can't open the DB, so this presents as a silent failure that's hard to diagnose.Fix (small, low-risk): add a
cygpath -mconversion inagmsg_db_path(), mirroring the existingcygpath -whandling inagmsg_sql_readfile_pathin the same file.-myields theC:/Users/...mixed (forward-slash) form, which both Git Bash[ -f ]tests andsqlite3.exeaccept. No-op off Windows:Since
agmsg_db_pathis the single chokepoint, this one change fixes every DB-backed script. I can open a PR for this.② [BUG]
watch.shsurvives a DB-open failure silentlyWhen the DB can't be opened (see ①),
watch.shkeeps running and emits nothing, so the operator can't tell receiving is dead. Suggestion: asqlite3 "$DB" 'SELECT 1;'health check at startup (and/or periodically) that prints a singleERROR: cannot open message DB <path>line to stdout on failure.③ [FEATURE] catch-up drain of unread inbox on watcher attach
The monitor (
watch.sh) streams only messages that arrive after attach. A message queued before the watcher attaches is missed — e.g. spawning a worker and immediately sending it a task: the worker reportsREADYbut never sees/acts on the queued task, so orchestration has to wait forREADYand then send live. Suggestion: on attach, drain & emit unread inbox once before entering the live stream.④ [BUG]
despawnineffective for non-tmux (OS-terminal) spawns on Windowsspawnvia an OS terminal /AGMSG_TERMINALtemplate does not write a placement record, sodespawn --forceexits withno placement recordand does nothing; gracefuldespawnis also a no-op when no live actas lock is held. The result is that a spawned member can only be removed withleave.sh(de-register) plus manually closing the window. Suggestion: record placement (or at least launch metadata) for OS-terminal spawns sodespawncan de-register consistently.⑤ [FEATURE] length guard in
send.shLong bodies sent over agmsg clutter the recipient inbox / terminal. Suggestion: a max-length guard in
send.sh(e.g. warn + refuse over ~2KB, nudging toward a file reference) for the "short notification + payload in a file" pattern.Thanks for agmsg — the daemonless SQLite design works well; these are all Windows/Git-Bash edges. ① in particular is a small change with a big payoff on Windows.