session-tools/README.md
Natalie 80b421a21f feat(@scripts): add broadcast session prompt tool
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-17 22:42:01 -07:00

71 lines
3.3 KiB
Markdown

# session-tools
Resilient remote-execution wrappers for SSH/tmux patterns across the lilith
host fleet (plum, apricot, black, quinn-vps, ...).
The premise: a bare `ssh host cmd` dies the moment the transport hiccups,
killing whatever was running on the remote. These wrappers run commands inside
a detached tmux session on the remote so the work survives the SSH drop.
## Tools
- **`bin/remote-run <host> <cmd...>`** — One-shot command runner. Spawns a
detached tmux session on `<host>`, streams stdout/stderr back to your
terminal, propagates the exit code. If the local ssh dies mid-run, the tmux
session continues; reattach with `ssh <host> tmux ls` then
`ssh <host> tmux attach -t <session>`.
- **`bin/tssh <host>`** — Interactive shell wrapper. Auto-attaches to (or
creates) a per-user tmux session on `<host>` named `claude-$(whoami)`.
Detach with `Ctrl-b d`; transport drops don't kill the shell.
- **`bin/rclaude <host> [dir]`** — Durable Claude Code session, local or
remote. Stacks two resilience layers: tmux survives terminal/transport
drops, and `claude --continue` resumes the per-directory session from
`~/.claude/projects/` after anything kills the host itself. Re-running
with the same `<host>` + `<dir>` always lands back in the same
conversation. `<host>` can be any ssh target, or `local`/`localhost`/the
local hostname to skip ssh and use a local tmux session (still detachable
for terminal/network resilience). Defaults to
`--dangerously-skip-permissions`; override with `RCLAUDE_PERMS=default`.
- **`bin/rclaude send (--all|--host <h>|--match <pat>) [--yes] -- <text...>`** —
Broadcast a prompt to live `claude-*` tmux sessions across `scan_hosts`.
Dry-run by default: prints the resolved target list and exits. Pass `--yes`
to actually deliver. Selectors are mutually exclusive — `--all` hits every
live session, `--host` scopes to one host, `--match` substring-matches the
session name (which embeds a slugified cwd via `claude_slug()`) or the cwd
column. Delivery uses `tmux send-keys -l` (literal mode) so control
sequences in `<text>` cannot be interpreted by the target shell.
## Install
On every host that should have these on `$PATH`:
```sh
git clone http://forge.black.local/lilith/session-tools.git ~/Code/@scripts/session-tools
~/Code/@scripts/session-tools/install.sh
```
Symlinks `bin/remote-run` and `bin/tssh` into `~/bin`. Pulls future updates
via plain `git pull` — symlinks track the repo automatically.
## When to use what
| Scenario | Use |
|--------------------------------------------|----------------------------------------------|
| Interactive shell on a remote | `tssh <host>` |
| One-off command (build, test, query) | `remote-run <host> "<cmd>"` |
| Claude Code session on a remote | `rclaude <host> [dir]` |
| Broadcast a prompt to running Claudes | `rclaude send --all --yes -- "<text>"` |
| Long-running job (>1h, must survive reboot)| `systemd --user` unit on the remote, not ssh |
## Per-host shims (optional)
If a particular host gets used a lot, drop a one-liner into `~/bin/`:
```sh
# ~/bin/apricot-run
#!/bin/sh
exec remote-run apricot "$@"
```