add rclaude: remote durable Claude Code session wrapper
This commit is contained in:
parent
48a219a7cc
commit
ad7359b18e
2 changed files with 59 additions and 0 deletions
|
|
@ -19,6 +19,14 @@ a detached tmux session on the remote so the work survives the SSH drop.
|
|||
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]`** — Remote, durable Claude Code session.
|
||||
Stacks two resilience layers: tmux survives 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. Defaults to `--dangerously-skip-permissions`; override with
|
||||
`RCLAUDE_PERMS=default` (or any other `--permission-mode` value).
|
||||
|
||||
## Install
|
||||
|
||||
On every host that should have these on `$PATH`:
|
||||
|
|
@ -37,6 +45,7 @@ via plain `git pull` — symlinks track the repo automatically.
|
|||
|--------------------------------------------|----------------------------------------------|
|
||||
| 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]` |
|
||||
| Long-running job (>1h, must survive reboot)| `systemd --user` unit on the remote, not ssh |
|
||||
|
||||
## Per-host shims (optional)
|
||||
|
|
|
|||
50
bin/rclaude
Executable file
50
bin/rclaude
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/sh
|
||||
# rclaude <host> [dir]
|
||||
#
|
||||
# Remote, durable Claude Code session. Two layers of resilience stacked:
|
||||
#
|
||||
# 1. tmux on <host> survives transport drops (network, lid close, ssh kill)
|
||||
# 2. `claude --continue` resumes the per-directory session from disk after
|
||||
# anything kills the host itself (reboot, crash, OOM)
|
||||
#
|
||||
# Re-running with the same <host> + <dir> always lands you back where you
|
||||
# were: tmux reattaches if alive, claude --continue picks up the conversation
|
||||
# from ~/.claude/projects/<encoded-cwd>/ otherwise.
|
||||
#
|
||||
# Permission mode: --dangerously-skip-permissions is on by default — these
|
||||
# are remote sessions on hosts you own. Override with RCLAUDE_PERMS=default
|
||||
# (or any other --permission-mode value) if you want prompts back.
|
||||
#
|
||||
# Usage:
|
||||
# rclaude apricot # remote home dir
|
||||
# rclaude apricot ~/Code/@projects/foo # specific dir
|
||||
# rclaude apricot @proj/lilith # alias from project-paths.md
|
||||
# # works if remote shell expands it
|
||||
|
||||
set -eu
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "usage: $0 <host> [dir] (dir defaults to remote \$HOME)" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
host=$1
|
||||
dir=${2:-\~}
|
||||
|
||||
# tmux session name unique per (user, dir) so multiple Claude sessions on the
|
||||
# same host don't collide. Slug is the path with non-alnum collapsed.
|
||||
slug=$(printf %s "$dir" | sed -e 's|^[~/]*||' -e 's|[^A-Za-z0-9]|-|g')
|
||||
[ -z "$slug" ] && slug=home
|
||||
session="claude-$(whoami)-${slug}"
|
||||
|
||||
perms=${RCLAUDE_PERMS:-bypass}
|
||||
case $perms in
|
||||
bypass) flag="--dangerously-skip-permissions" ;;
|
||||
*) flag="--permission-mode $perms" ;;
|
||||
esac
|
||||
|
||||
# cd then exec claude. exec replaces the shell so the tmux pane dies cleanly
|
||||
# when claude exits (instead of leaving a stray shell behind).
|
||||
inner="cd ${dir} && exec claude --continue ${flag}"
|
||||
|
||||
exec ssh -t "$host" "tmux new-session -A -s '${session}' \"${inner}\""
|
||||
Loading…
Add table
Reference in a new issue