TazPod: Dotfiles Detail

Level 3 (Detail) โ€” Shell environment provisioning inside the container.

Concept

dotfiles/ defines the shell personality inside the container. The .bashrc is the control plane that reconnects the disposable container to persistent operator state under /workspace/.tazpod/.

.bashrc

File: dotfiles/.bashrc

NVM Initialization

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

Shell Tools

  • Starship: eval "$(starship init bash)"
  • Zoxide: eval "$(zoxide init bash)"
  • FZF: eval "$(fzf --bash)"

TazPod Shell Function

tazpod() {
    if [ "$1" == "env" ]; then
        eval "$(command tazpod __internal_env 2>/dev/null)"
        echo "๐Ÿ”„ Enclave environment variables refreshed."
        return 0
    fi
    command tazpod "$@";
    local res=$?;
    if [ "$1" == "unlock" ] || [ "$1" == "pull" ] || [ "$1" == "sync" ] || [ "$1" == "login" ] || [ "$1" == "lock" ]; then
        if [ "$1" == "lock" ]; then sleep 0.1; fi
        eval "$(command tazpod __internal_env 2>/dev/null)"
    fi
    return $res;
}

Vault Auto-Lock on Last Shell Exit

Implemented finally in v0.3.22 (TD-027). The earlier pgrep-based counter was too fragile because background subshells and orphaned docker exec sessions could be miscounted. The final implementation uses marker files under /tmp/.tazpod-shells/:

_TAZPOD_SHELL_MARKER_DIR=/tmp/.tazpod-shells
_TAZPOD_SHELL_MARKER="$_TAZPOD_SHELL_MARKER_DIR/$$"
mkdir -p "$_TAZPOD_SHELL_MARKER_DIR"

_clean_stale_tazpod_markers() {
    for f in "$_TAZPOD_SHELL_MARKER_DIR"/*; do
        [ -e "$f" ] || continue
        pid="${f##*/}"
        [ -d "/proc/$pid" ] || { rm -f "$f"; continue; }
        [ "$(cat "/proc/$pid/comm" 2>/dev/null)" = "bash" ] || { rm -f "$f"; continue; }
    done
}

_clean_stale_tazpod_markers
printf 'tty=%s sid=%s\n' "$(tty 2>/dev/null || printf 'none')" "$(ps -o sid= -p $$ 2>/dev/null | tr -d ' ')" > "$_TAZPOD_SHELL_MARKER"

_vault_maybe_lock() {
    rm -f "$_TAZPOD_SHELL_MARKER"
    _clean_stale_tazpod_markers
    if ! find "$_TAZPOD_SHELL_MARKER_DIR" -mindepth 1 -maxdepth 1 -type f | read -r _; then
        command tazpod lock
    fi
}
trap '_vault_maybe_lock' EXIT

Each interactive shell creates its own marker file. On exit it removes that marker, cleans stale markers left by dead PIDs, and only runs tazpod lock when no marker files remain. This makes the behavior resistant to:

  • background subshells (for example plugin bootstrap or shell helper jobs)
  • orphaned docker exec sessions whose parent process died
  • operators keeping two interactive shells open at the same time

Observed behavior after the final fix:

  • one shell only โ†’ exit locks the vault
  • two shells open โ†’ first exit does nothing, second exit locks
  • stale shell markers are removed on next shell start

Tailscale Auto-Start

When a new interactive shell opens, .bashrc checks if Tailscale is already running via the daemon socket. If not, it launches start.sh in background (detached via setsid) and prints a rocket message. On second shells (already running), it silently runs update-hosts.sh to refresh /etc/hosts with current MagicDNS names.

_TAILSCALE_SOCK="/workspace/AGENTS.ctx/tools/tailscale/state/tailscaled.sock"
if ! tailscale --socket="${_TAILSCALE_SOCK}" status >/dev/null 2>&1; then
    setsid /workspace/AGENTS.ctx/tools/tailscale/start.sh > /tmp/tailscale-startup.log 2>&1 &
    echo "  ๐Ÿš€ Tailscale auto-start launched (log: /tmp/tailscale-startup.log)"
else
    # Tailscale already running โ€” refresh /etc/hosts silently
    /workspace/AGENTS.ctx/tools/tailscale/update-hosts.sh >/dev/null 2>&1 &
fi
unset _TAILSCALE_SOCK

DNS fix chain (2026-05-28): start.sh now applies --stateful-filtering=false and --accept-dns=false to resolve Tailscale v1.66+ UDP DNS drops from Docker bridge interfaces. After joining the tailnet, update-hosts.sh syncs *.magellanic-gondola.ts.net names to /etc/hosts so curl, vault CLI, getent hosts resolve natively.

The daemon takes 2-4 seconds to start (minting OAuth auth key + tailscale up). The shell prompt appears immediately; DNS and routing become available shortly after.

Auto-Load on Shell Start

If the vault is already unlocked when a new shell opens, secrets are loaded automatically:

if mountpoint -q /home/tazpod/secrets; then
    eval "$(command tazpod __internal_env 2>/dev/null)"
fi

The bashrc creates symlinks from /workspace/.tazpod/ into $HOME for tool configs that must survive container recreation:

Symlink TargetSource
~/.pi/workspace/.tazpod/.pi
~/.omp/workspace/.tazpod/.omp
~/.gemini/workspace/.tazpod/.gemini
~/.claude/workspace/.tazpod/.claude
~/.antigravity/workspace/.tazpod/.antigravity
~/.antigravitycli/workspace/.tazpod/.antigravitycli
~/.aws/workspace/.tazpod/.aws
~/.opencode/workspace/.tazpod/.opencode
~/.config/opencode/workspace/.tazpod/.opencode/config
~/.local/share/opencode/workspace/.tazpod/.opencode/data
~/.local/state/opencode/workspace/.tazpod/.opencode/state
~/.cache/opencode/workspace/.tazpod/.opencode/cache

OpenCode Auto-Seeding

The bashrc seeds OpenCode on first run:

  1. Creates tui.json with mouse disabled if missing
  2. Creates opencode.json with standard Gemini CLI models if missing
  3. Creates minimal package.json in config dir if needed

.tmux.conf

File: dotfiles/.tmux.conf

FeatureSetting
Colors256-color (screen-256color)
Mouseon
Vi modevi copy mode
ClipboardOSC 52 (set-clipboard external)
History10000 lines
Escape time0ms
Status interval5s

.config/starship.toml

Powerline-style prompt with:

  • OS icon + username
  • Directory (truncated)
  • Git branch + status
  • Kubernetes context
  • Python virtualenv
  • Node.js version
  • Command duration
  • Line break + prompt char

.config/zellij/config.kdl

Zellij multiplexer config:

  • mouse_mode = true
  • copy_on_select = true
  • scrollback_editor = /usr/bin/nvim
  • OSC 52 clipboard enabled

.config/opencode/tui.json

OpenCode TUI config โ€” mouse disabled, Metro theme.

.local/bin/opencode-osc52-clipboard

Clipboard bridge for Docker environments. Uses OSC 52 escape sequence to copy from inside the container to the host clipboard.

.config/nvim/

LazyVim-based Neovim setup with clipboard integration via opencode-osc52-clipboard.

See Also