Skip to content

Latest commit

 

History

56 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ward

Ward is a disposable Arch Linux environment for pi and its shared tmux server. It runs as a rootless Podman container under the user systemd instance. It exists to give a coding agent an exact, always-current toolchain that can be rebuilt and discarded at any time, without touching host state.

The image builds from archlinux:latest and installs the full package set in one transaction at build time; a daily rebuild keeps it current. The container runs with dropped capabilities and private namespaces; its writable root is discarded on stop, and only declared bind mounts persist. The tmux server runs in the container and exposes its socket, so sessions are driven by host clients. Networking is shared with the host; Ward isolates state, not the network.

Host setup

sudo pacman --needed -S github-cli libsecret openssh podman tmux
systemctl --user enable --now ssh-agent.socket podman.socket

The ward unit syncs the ward-github-token, ward-brave-api-key, ward-bsky-app-password, and ward-mastodon-access-token podman secrets from the host keyring (secret-tool) at every start and exposes them in the container as GH_TOKEN, BRAVE_API_KEY, BSKY_APP_PASSWORD, and MASTODON_ACCESS_TOKEN. The start fails when any keyring entry is missing. Store them before starting Ward:

printf %s "$GH_TOKEN" | secret-tool store --label='Ward' service gh:github.com
printf %s "$BRAVE_API_KEY" | secret-tool store --label='Ward' service brave
printf %s "$BSKY_APP_PASSWORD" | secret-tool store --label='Ward' service bluesky
printf %s "$MASTODON_ACCESS_TOKEN" | secret-tool store --label='Ward' service mastodon

Deploy

From the repository root:

install -d -m 0755 \
    "$HOME/.cargo" \
    "$HOME/.cache/uv" \
    "$HOME/.local/share/pnpm" \
    "$HOME/.local/share/uv"
install -d -m 0700 "$HOME/.config/containers/systemd" "$HOME/.config/systemd/user"
ln -sT "$PWD" "$HOME/.config/containers/systemd/ward"
ln -sT "$PWD/ward-build.timer" "$HOME/.config/systemd/user/ward-build.timer"
systemctl --user daemon-reload
systemctl --user start ward-build.service
systemctl --user start ward.service
systemctl --user enable --now ward-build.timer

Updates

ward-build.timer builds daily in the background (Persistent=true catches up after downtime). Every run pulls archlinux:latest; when the digest is unchanged, every layer is a cache hit and the build installs nothing. Real rebuilds happen only when Arch publishes a new base image or the Containerfile changes — the single pacman -Syu transaction then runs against current mirrors. Package state advances when the base image moves, not at each build.

A build never restarts the running container: it keeps its current root, and the new image is used the next time ward.service starts — after a reboot, or when applied manually below. Updates land when you choose, not mid-session. Superseded builds remain in storage as dangling images; podman image prune -f removes all dangling images, spares the live build cache (images with children), and never removes an image in use by a container.

ward-build.timer is a plain systemd unit, not a quadlet file, so it installs under ~/.config/systemd/user/.

Apply

systemctl --user daemon-reload
systemctl --user restart ward-build.service &&
systemctl --user restart ward.service

The container is restarted only after a successful build; sessions in it end at that moment.

Start a session

tmux -S "$XDG_RUNTIME_DIR/ward/tmux.sock"

Remove

systemctl --user disable --now ward-build.timer
systemctl --user stop ward.service ward-build.service
rm -- "$HOME/.config/containers/systemd/ward" \
      "$HOME/.config/systemd/user/ward-build.timer"
systemctl --user daemon-reload
podman image rm localhost/ward:latest
podman image prune -f
podman secret rm ward-github-token ward-brave-api-key

About

Magical barrier

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages