setup: Add script to share agent state via container home symlinks
This commit is contained in:
parent
a3aa03e14d
commit
d110942710
2 changed files with 119 additions and 0 deletions
14
README.md
14
README.md
|
|
@ -31,6 +31,14 @@ source ~/Projects/agent-container/agent.aliases
|
||||||
|
|
||||||
This makes the `opencode`, `claude`, `pi`, and `agent-container` commands available in new sessions, plus the `opencode-local`, `claude-local`, and `pi-local` variants that run the tools directly on the host.
|
This makes the `opencode`, `claude`, `pi`, and `agent-container` commands available in new sessions, plus the `opencode-local`, `claude-local`, and `pi-local` variants that run the tools directly on the host.
|
||||||
|
|
||||||
|
Optionally run the setup script to share agent state (`.claude`, `.pi`, `.agents`, OpenCode state, ...) between the container and the host:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
~/Projects/agent-container/setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
It moves existing state into the container home and symlinks it back into `$HOME`, so containerized tools and the `*-local` variants share logins, settings, and history. See "Sharing agent state between host and container via symlinks" below. The script is safe to re-run and skips items it cannot handle safely.
|
||||||
|
|
||||||
The container home directory at `$XDG_DATA_HOME/agent-container/container-home/` serves as a central `$HOME` inside every container, independent of which project directory you start in. Everything written to `$HOME` inside the container persists there.
|
The container home directory at `$XDG_DATA_HOME/agent-container/container-home/` serves as a central `$HOME` inside every container, independent of which project directory you start in. Everything written to `$HOME` inside the container persists there.
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
@ -85,6 +93,8 @@ To remove all containers, the image, and the persistent home directory:
|
||||||
agent-container purge
|
agent-container purge
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that this also deletes the shared agent state that lives in the container home (`.claude`, `.pi`, ...). The symlinks in your `$HOME` will dangle afterwards.
|
||||||
|
|
||||||
## Sharing host config files via hard links
|
## Sharing host config files via hard links
|
||||||
|
|
||||||
The container home at `~/.local/share/agent-container/container-home/` is mounted as `/home/<username>` inside every container. You can hard link files from your real `$HOME` into this directory so the container sees them without copying or syncing.
|
The container home at `~/.local/share/agent-container/container-home/` is mounted as `/home/<username>` inside every container. You can hard link files from your real `$HOME` into this directory so the container sees them without copying or syncing.
|
||||||
|
|
@ -102,6 +112,10 @@ Avoid linking sensitive files such as `~/.ssh/id_*` or `~/.gnupg/` -- keeping th
|
||||||
|
|
||||||
## Sharing agent state between host and container via symlinks
|
## Sharing agent state between host and container via symlinks
|
||||||
|
|
||||||
|
The repository ships a `setup.sh` script that automates the following for `.claude`,
|
||||||
|
`.claude.json`, `.pi`, `.agents`, and the OpenCode state directories. The manual
|
||||||
|
recipe for any other directory looks like this:
|
||||||
|
|
||||||
State directories such as `.claude/`, `.pi/`, or `.agents/` can be shared between the
|
State directories such as `.claude/`, `.pi/`, or `.agents/` can be shared between the
|
||||||
containerized tools (`claude`, `pi`, `opencode`) and their local variants
|
containerized tools (`claude`, `pi`, `opencode`) and their local variants
|
||||||
(`claude-local`, `pi-local`, `opencode-local`). Keep the real data in the container home
|
(`claude-local`, `pi-local`, `opencode-local`). Keep the real data in the container home
|
||||||
|
|
|
||||||
105
setup.sh
Executable file
105
setup.sh
Executable file
|
|
@ -0,0 +1,105 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Set up shared agent state for agent-container.
|
||||||
|
#
|
||||||
|
# Moves agent state (Claude Code, Pi, OpenCode) from the real $HOME into the
|
||||||
|
# container home and symlinks it back, so the containerized tools (claude, pi,
|
||||||
|
# opencode) and the local variants (claude-local, pi-local, opencode-local)
|
||||||
|
# share logins, settings, and history. See README.md, section "Sharing agent
|
||||||
|
# state between host and container via symlinks".
|
||||||
|
#
|
||||||
|
# Safe to re-run: already shared items are detected and left alone.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||||
|
CONTAINER_HOME="$XDG_DATA_HOME/agent-container/container-home"
|
||||||
|
|
||||||
|
# State directories to share. Created in the container home (and linked into
|
||||||
|
# $HOME) even if they don't exist yet, so both sides share from the start.
|
||||||
|
DIRS=(
|
||||||
|
.claude
|
||||||
|
.pi
|
||||||
|
.agents
|
||||||
|
.config/opencode
|
||||||
|
.local/share/opencode
|
||||||
|
)
|
||||||
|
|
||||||
|
# Single files to share. Only linked when they exist on one side, tools create
|
||||||
|
# them on first use.
|
||||||
|
FILES=(
|
||||||
|
.claude.json
|
||||||
|
)
|
||||||
|
|
||||||
|
info() { printf ' %s\n' "$*"; }
|
||||||
|
warn() { printf ' warning: %s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
# Print the action taken for an item, shared by both helpers below.
|
||||||
|
_report() {
|
||||||
|
local action="$1" item="$2"
|
||||||
|
case "$action" in
|
||||||
|
moved) info "moved $item into the container home, symlinked from \$HOME" ;;
|
||||||
|
linked) info "linked $item (container home already had it)" ;;
|
||||||
|
created) info "created $item in the container home, symlinked from \$HOME" ;;
|
||||||
|
ok) info "ok $item (already shared)" ;;
|
||||||
|
skip) info "skip $item (does not exist yet, the tool will create it)" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
share_item() {
|
||||||
|
local item="$1" must_exist="$2"
|
||||||
|
local host="$HOME/$item" target="$CONTAINER_HOME/$item"
|
||||||
|
|
||||||
|
if [ -L "$host" ]; then
|
||||||
|
case "$(readlink -f "$host")" in
|
||||||
|
"$CONTAINER_HOME"/*)
|
||||||
|
_report ok "$item"
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
warn "$item is a symlink to $(readlink "$host"), not touching it"
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e "$host" ] && [ -e "$target" ]; then
|
||||||
|
warn "$item exists in both \$HOME and the container home"
|
||||||
|
warn "reconcile the two copies manually, then re-run this script"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -e "$host" ] && [ ! -e "$target" ]; then
|
||||||
|
if [ "$must_exist" = "yes" ]; then
|
||||||
|
_report skip "$item"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
mkdir -p "$target"
|
||||||
|
_report created "$item"
|
||||||
|
elif [ -e "$host" ]; then
|
||||||
|
mkdir -p "$(dirname "$target")"
|
||||||
|
mv "$host" "$target"
|
||||||
|
_report moved "$item"
|
||||||
|
else
|
||||||
|
_report linked "$item"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$host")"
|
||||||
|
ln -s "$target" "$host"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
printf 'Sharing agent state via %s\n\n' "$CONTAINER_HOME"
|
||||||
|
|
||||||
|
local item
|
||||||
|
for item in "${DIRS[@]}"; do share_item "$item" no; done
|
||||||
|
for item in "${FILES[@]}"; do share_item "$item" yes; done
|
||||||
|
|
||||||
|
if [ -f "$HOME/.gitconfig" ] && [ ! -e "$CONTAINER_HOME/.gitconfig" ]; then
|
||||||
|
printf '\n'
|
||||||
|
info "Tip: share your git config too (see README):"
|
||||||
|
info " ln $HOME/.gitconfig $CONTAINER_HOME/.gitconfig"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue