What happened?
cc-connect chat-daemon-daemon does not terminate on SIGTERM — it must be SIGKILL-ed. The sibling cc-connect host-bg-daemon does terminate cleanly on SIGTERM (its atexit / signal handler unlinks state and exits). The chat side appears to block somewhere in its cleanup path.
User-visible consequence: every time you close a TUI tab (or the TUI itself crashes / is force-quit) the chat-daemon for that room is left running. Over a few hours of normal use we accumulated 9 orphan chat-daemon-daemon processes (3h+ old at the top of the list) plus their stale ${TMPDIR}/cc-connect-${UID}/active-rooms/<topic>.active files. The hook's PID-liveness sweep can't help here because the orphan process is still alive — it just shouldn't be.
Reproduction
cc-connect room start (spawns chat-daemon-daemon + host-bg-daemon).
kill <chat-daemon-pid> (SIGTERM).
ps -p <chat-daemon-pid> — process still running.
kill <host-bg-pid> (SIGTERM) on the same room — that one does exit.
kill -9 <chat-daemon-pid> — finally gone.
Reproduced today on main @ `be51e41` — sent SIGTERM to 16 daemons, 7 host-bg exited, 9 chat-daemon survived; SIGKILL cleaned them up.
cc-connect doctor output
```shell
[OK] identity.key at /Users/yijian/.cc-connect/identity.key is mode 0600
[OK] /var/folders/b_/lblpdcts7l13p015ws2145y80000gn/T/cc-connect-501/active-rooms is a directory with mode 0700
[OK] hook binary /Users/yijian/work/cc-connect/target/release/cc-connect-hook exists and is executable
[OK] mcp server /Users/yijian/.local/bin/cc-connect-mcp exists and is executable (registered in /Users/yijian/.claude.json)
[--] if Claude Code says 'cc-connect MCP not found' even though this check passed, restart Claude Code so it re-reads its config on launch.
4 ok, 0 warn, 0 fail
```
cc-connect version / commit
`v0.4.2-alpha-18-gbe51e41` (HEAD of `main`, commit `be51e41`)
rustc version
`rustc 1.95.0 (59807616e 2026-04-14)`
Operating system
macOS (Apple Silicon) — Darwin 24.6.0
Anything else?
Hypothesis (not yet confirmed by code read): the chat-daemon's shutdown path likely awaits one of:
- gossip-topic leave ack from the iroh runtime,
- IPC `accept()` loop on `chat.sock` finishing,
- chat_session worker tasks draining,
and one of those is not signal-aware. host-bg-daemon doesn't have the IPC socket or chat_session, which is consistent with it shutting down clean.
Suggested fix direction: install a tokio `signal::ctrl_c` / unix-signal listener that flips a shutdown `CancellationToken`; thread the token into the IPC accept loop and any blocking wait in chat_session so they bail. Then the existing `atexit` unlink of `.active` runs as a normal exit path.
Related UX impact: `Ctrl-W` close-tab in the TUI presumably already SIGTERMs the daemon (per the README's "prompts whether to also stop the daemon"); if so, choosing "yes, stop the daemon" silently does nothing and the daemon survives. Worth verifying as part of the fix.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
What happened?
cc-connect chat-daemon-daemondoes not terminate onSIGTERM— it must beSIGKILL-ed. The siblingcc-connect host-bg-daemondoes terminate cleanly onSIGTERM(itsatexit/ signal handler unlinks state and exits). The chat side appears to block somewhere in its cleanup path.User-visible consequence: every time you close a TUI tab (or the TUI itself crashes / is force-quit) the chat-daemon for that room is left running. Over a few hours of normal use we accumulated 9 orphan
chat-daemon-daemonprocesses (3h+ old at the top of the list) plus their stale${TMPDIR}/cc-connect-${UID}/active-rooms/<topic>.activefiles. The hook's PID-liveness sweep can't help here because the orphan process is still alive — it just shouldn't be.Reproduction
cc-connect room start(spawns chat-daemon-daemon + host-bg-daemon).kill <chat-daemon-pid>(SIGTERM).ps -p <chat-daemon-pid>— process still running.kill <host-bg-pid>(SIGTERM) on the same room — that one does exit.kill -9 <chat-daemon-pid>— finally gone.Reproduced today on main @ `be51e41` — sent SIGTERM to 16 daemons, 7 host-bg exited, 9 chat-daemon survived; SIGKILL cleaned them up.
cc-connect doctor output
```shell
[OK] identity.key at /Users/yijian/.cc-connect/identity.key is mode 0600
[OK] /var/folders/b_/lblpdcts7l13p015ws2145y80000gn/T/cc-connect-501/active-rooms is a directory with mode 0700
[OK] hook binary /Users/yijian/work/cc-connect/target/release/cc-connect-hook exists and is executable
[OK] mcp server /Users/yijian/.local/bin/cc-connect-mcp exists and is executable (registered in /Users/yijian/.claude.json)
[--] if Claude Code says 'cc-connect MCP not found' even though this check passed, restart Claude Code so it re-reads its config on launch.
4 ok, 0 warn, 0 fail
```
cc-connect version / commit
`v0.4.2-alpha-18-gbe51e41` (HEAD of `main`, commit `be51e41`)
rustc version
`rustc 1.95.0 (59807616e 2026-04-14)`
Operating system
macOS (Apple Silicon) — Darwin 24.6.0
Anything else?
Hypothesis (not yet confirmed by code read): the chat-daemon's shutdown path likely awaits one of:
and one of those is not signal-aware. host-bg-daemon doesn't have the IPC socket or chat_session, which is consistent with it shutting down clean.
Suggested fix direction: install a tokio `signal::ctrl_c` / unix-signal listener that flips a shutdown `CancellationToken`; thread the token into the IPC accept loop and any blocking wait in chat_session so they bail. Then the existing `atexit` unlink of `.active` runs as a normal exit path.
Related UX impact: `Ctrl-W` close-tab in the TUI presumably already SIGTERMs the daemon (per the README's "prompts whether to also stop the daemon"); if so, choosing "yes, stop the daemon" silently does nothing and the daemon survives. Worth verifying as part of the fix.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com