viberun CLI
Project description
viberun
viberun is a CLI-first, agent-native app host. Run viberun <app> locally and get dropped into an agent session inside a persistent Ubuntu container on a remote host. App data is stored under /home/viberun and survives container restarts or image updates.
Quick start (end-to-end)
You need a local machine with ssh and a reachable Ubuntu host (VM or server) that you can SSH into with sudo access.
1) Install the CLI
curl -fsSL https://viberun.sh | bash
Verify:
viberun --version
Optional overrides (advanced):
curl -fsSL https://viberun.sh | bash -s -- --nightly
curl -fsSL https://viberun.sh | bash -s -- --dir ~/.local/bin --bin viberun
Or with env vars:
curl -fsSL https://viberun.sh | VIBERUN_INSTALL_DIR=~/.local/bin VIBERUN_INSTALL_BIN=viberun bash
2) Bootstrap a host (once per VM)
Use any SSH host alias (for example, myhost in ~/.ssh/config):
viberun bootstrap myhost
Optional: set it as your default host (and agent) so you can omit @host later:
viberun config --host myhost --agent codex
3) Start your first app
viberun hello-world
If this is the first run, the server will prompt to create the container. Press Enter to accept.
Detach without stopping the agent: Ctrl-\ . Reattach later with viberun hello-world.
Paste clipboard images into the session with Ctrl-V; viberun uploads the image and inserts a /tmp/viberun-clip-*.png path.
4) Hello-world prompt (paste inside the session)
Create a beautiful hello-world web app with a simple, tasteful landing page.
5) Open the app
While the session is active, viberun starts a localhost proxy to the host port. The agent will print a URL like:
http://localhost:8080
Open it in your browser.
If you've configured app URLs, viberun <app> url shows the HTTPS address.
Common commands
viberun myapp
viberun myapp@hostb
viberun --forward-agent myapp
viberun myapp shell
viberun myapp snapshot
viberun myapp snapshots
viberun myapp restore latest
viberun myapp url
viberun myapp users
viberun myapp --delete -y
viberun myapp update
viberun bootstrap [<host>]
viberun proxy setup
viberun users list
viberun wipe
viberun config --host myhost --agent codex
viberun version
Table of contents
Git setup
Git, SSH, and the GitHub CLI are installed in containers. viberun seeds git config --global user.name and user.email from your local Git config into a host-managed config file that is mounted into each app container and applied on startup. This removes the common "first commit" setup step without auto-authing you.
Choose one of these auth paths:
- SSH (agent forwarding): Run
viberun --forward-agent <app>. For existing apps, runviberun <app> updateonce to recreate the container with the agent socket mounted. Thenssh -T git@github.cominside the container to verify access. - HTTPS (GitHub CLI): Run
gh auth loginand choose HTTPS, thengh auth setup-git. Verify withgh auth status.
If you update your local Git identity later, restart the app container (or run viberun <app> update) to re-apply the new values on startup.
Development
This repo is Go-first and uses mise for tool and task orchestration.
Setup
mise install
Build
mise exec -- go build ./cmd/viberun
mise exec -- go build ./cmd/viberun-server
Run locally
mise exec -- go run ./cmd/viberun -- --help
mise exec -- go run ./cmd/viberun-server -- --help
Test and vet
mise exec -- go test ./...
mise exec -- go vet ./...
Container image
mise run build:image
# fallback: docker build -t viberun .
# proxy image (Caddy + auth):
docker build -f Dockerfile.proxy -t viberun-proxy .
E2E and integration
bin/viberun-e2e-local
bin/viberun-integration
Bootstrap in development
When you run viberun via go run (or a dev build), bootstrap defaults to staging the local server binary and building the container image locally. This is equivalent to:
viberun bootstrap --local --local-image myhost
Under the hood, it builds a viberun:dev image for the host architecture, streams it over ssh with docker save | docker load, and tags it as viberun:latest on the host.
If you want to explicitly pass a local server binary:
mise exec -- go build -o /tmp/viberun-server ./cmd/viberun-server
viberun bootstrap --local-path /tmp/viberun-server myhost
For the full build/test/E2E flow, see DEVELOPMENT.md.
Architecture
High-level flow
viberun <app>
-> ssh <host>
-> viberun-server <app>
-> docker container viberun-<app>
-> agent session (tmux)
container port 8080
-> host port (assigned per app)
-> ssh -L localhost:<port>
-> http://localhost:<port>
-> (optional) host proxy (Caddy)
-> https://<app>.<domain>
Core components
- Client:
viberunCLI on your machine. - Server:
viberun-serverexecuted on the host via SSH (no long-running daemon required). - Container:
viberun-<app>Docker container built from theviberun:latestimage. - Agent: runs inside the container in a tmux session (default provider:
codex). - Host RPC: local Unix socket used by the container to request snapshot/restore operations.
- Proxy (optional):
viberun-proxy(Caddy +viberun-auth) for app URLs and login.
Session lifecycle
viberun <app>resolves the host (from@hostor your default config) and runsviberun-serverover SSH.- The server creates the container if needed, or starts it if it already exists.
- The agent process is attached via
docker execinside a tmux session so it persists across disconnects. viberunsets up a local port forward so you can open the app onhttp://localhost:<port>.
Bootstrap pipeline
The bootstrap script (run on the host) does the following:
- Verifies the host is Ubuntu.
- Installs Docker (if missing) and enables it.
- Installs Btrfs tools (
btrfs-progs) for volume snapshots. - Pulls the
viberuncontainer image from GHCR (unless using local image mode). - Downloads and installs the
viberun-serverbinary.
If bootstrap is run from a TTY, it will offer to set up a public domain name (same as viberun proxy setup).
Useful bootstrap overrides:
VIBERUN_SERVER_REPO: GitHub repo for releases (defaultshayne/viberun).VIBERUN_SERVER_VERSION: release tag orlatest.VIBERUN_IMAGE: container image override.VIBERUN_PROXY_IMAGE: proxy container image override (for app URLs).VIBERUN_SERVER_INSTALL_DIR: install directory on the host.VIBERUN_SERVER_BIN: server binary name on the host.VIBERUN_SERVER_LOCAL_PATH: use a local server binary staged over SSH.VIBERUN_SKIP_IMAGE_PULL: skip pulling from GHCR (used for local builds).
Networking and ports
- Each app container exposes port
8080internally. - The host port is assigned per app (starting at
8080) and stored in the host server state. viberunopens an SSH local forward sohttp://localhost:<port>connects to the host port.- If the proxy is configured, apps can also be served over HTTPS at
https://<app>.<domain>(or a custom domain). Access requires login by default and can be made public per app.
App URLs and proxy
viberun can optionally expose apps via a host-side proxy (Caddy + viberun-auth).
Set it up once per host:
viberun proxy setup [<host>]
You'll be prompted for a base domain and public IP (for DNS), plus a primary username/password. Create an A record (or wildcard) pointing to the host's public IP.
After setup:
viberun <app> urlshows the current URL and access status.viberun <app> url --make-publicor--require-logintoggles access (default requires login).viberun <app> url --set-domain <domain>or--reset-domainmanages custom domains.viberun <app> url --disableor--enableturns the URL off/on.viberun <app> url --openopens the URL in your browser.viberun users ...manages login accounts;viberun <app> userscontrols who can access the app.
If URL settings change, run viberun <app> update to refresh VIBERUN_PUBLIC_URL and VIBERUN_PUBLIC_DOMAIN inside the container.
Snapshots and restore
Snapshots are Btrfs subvolume snapshots of the app's /home/viberun volume (auto-incremented versions).
On the host, each app uses a loop-backed Btrfs file under /var/lib/viberun/apps/<app>/home.btrfs.
viberun <app> snapshotcreates the nextvNsnapshot.viberun <app> snapshotslists versions with timestamps.viberun <app> restore <vN|latest>restores from a snapshot (latestpicks the highestvN).viberun <app> --delete -yremoves the container, the app volume + snapshots, and the host RPC directory.
Restore details:
- The host stops the container (if running) to safely unmount the volume.
- The current
@homesubvolume is replaced by a new writable snapshot of@snapshots/vN. - The container is started again, and s6 reloads services from
/home/viberun/.local/services.
Host RPC bridge
When you open a session, the server creates a Unix socket on the host and mounts it into the container at /var/run/viberun-hostrpc. The container uses it to request snapshot and restore operations. Access is protected by a per-session token file mounted alongside the socket.
Configuration and state
Local config lives at ~/.config/viberun/config.toml (or $XDG_CONFIG_HOME/viberun/config.toml) and stores:
default_hostagent_providerhosts(alias mapping)
Host server state lives at ~/.config/viberun/server-state.json (or $XDG_CONFIG_HOME/viberun/server-state.json) and stores the port mapping for each app.
Proxy config (when enabled) lives at /var/lib/viberun/proxy.toml (or $VIBERUN_PROXY_CONFIG_PATH) and stores the base domain, access rules, and users.
When enabled, the server injects VIBERUN_PUBLIC_URL and VIBERUN_PUBLIC_DOMAIN into containers.
Agents
Supported agent providers:
codex(default)claudegeminiampcode(alias:amp)opencode
Custom agents can be run via npx:<pkg> or uvx:<pkg> (for example, viberun --agent npx:@sourcegraph/amp@latest <app>).
Set globally with viberun config --agent <provider> or per-run with viberun --agent <provider> <app>.
To forward your local SSH agent into the container, use viberun --forward-agent <app>. For existing apps, run viberun <app> update once to recreate the container with the agent socket mounted.
Base skills are shipped in /opt/viberun/skills and symlinked into each agent's skills directory. User skills can be added directly to the agent-specific skills directory under /home/viberun.
Security model
- All control traffic goes over SSH; the server is invoked on demand and does not expose a network port.
- The host RPC socket is local-only and protected by filesystem permissions and a per-session token.
- Containers are isolated by Docker and only the app port is exposed.
- App URLs are optional: the proxy requires login by default and can be made public per app with
viberun <app> url --make-public.
Wipe (safety)
viberun wipe [<host>] deletes local config and wipes all viberun data on the host.
It requires a TTY and asks you to type WIPE.
On the host, wipe removes:
- All containers named
viberun-*, any containers usingviberunimages, and the proxy container (defaultviberun-proxy). - All
viberunimages (including the proxy image). - App data and snapshots under
/var/lib/viberun(including per-app Btrfs volumes). - Host RPC sockets in
/tmp/viberun-hostrpcand/var/run/viberun-hostrpc. /etc/viberun,/etc/sudoers.d/viberun-server, and/usr/local/bin/viberun-server.
Locally, it removes ~/.config/viberun/config.toml (and legacy config if present).
Repository layout
cmd/: Go entrypoints (viberun,viberun-server,viberun-auth).internal/: Core packages (config, server state, SSH args, target parsing, TUI helpers).bin/: Helper scripts for installs, integration/E2E flows, and container utilities.skills/: Codex skill definitions used inside containers.config/: Shell/TMUX/Starship config, auth assets, and runtime configs.Dockerfile: Base container image definition.Dockerfile.proxy: Proxy image definition (Caddy + auth).
Troubleshooting
unsupported OS: ... expected ubuntu: bootstrap currently supports Ubuntu only.docker is required but was not found in PATH: install Docker on the host or re-run bootstrap.missing btrfs on host: rerun bootstrap to installbtrfs-progsand ensure sudo access.no host provided and no default host configured: runviberun config --host myhostor usemyapp@host.container image architecture mismatch: delete and recreate the app (viberun <app> --delete -y).proxy is not configured: runviberun proxy setup(then retryviberun <app> url).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file viberun-0.3.4.tar.gz.
File metadata
- Download URL: viberun-0.3.4.tar.gz
- Upload date:
- Size: 38.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
059c1525cc2bfeb6ddccddc45ae1205fffa23faecdeebbda31ae38636ba1a314
|
|
| MD5 |
9c7fc1e8d2fe4c6d0e4a78f7b9375ab3
|
|
| BLAKE2b-256 |
a043833b0133b86c7fede29740773e8e626bb7bdc456079be9e5dbd390ad54dc
|
Provenance
The following attestation bundles were made for viberun-0.3.4.tar.gz:
Publisher:
release.yml on shayne/viberun
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
viberun-0.3.4.tar.gz -
Subject digest:
059c1525cc2bfeb6ddccddc45ae1205fffa23faecdeebbda31ae38636ba1a314 - Sigstore transparency entry: 843314181
- Sigstore integration time:
-
Permalink:
shayne/viberun@6cf9ca9ad3240b0b3520bc9c883cc0a20945cb40 -
Branch / Tag:
refs/tags/v0.3.4 - Owner: https://github.com/shayne
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6cf9ca9ad3240b0b3520bc9c883cc0a20945cb40 -
Trigger Event:
push
-
Statement type:
File details
Details for the file viberun-0.3.4-py3-none-any.whl.
File metadata
- Download URL: viberun-0.3.4-py3-none-any.whl
- Upload date:
- Size: 38.8 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7f05463fa22ec20adee69621afd9eb131233d49951285d72a2bd3db4080cea8
|
|
| MD5 |
48998f73cff6738c1bcaff7a868044c1
|
|
| BLAKE2b-256 |
cb30b876dbf6b817cc9178d1ca31cfc8e57fe435004577cb737bfaff5dd3dda5
|
Provenance
The following attestation bundles were made for viberun-0.3.4-py3-none-any.whl:
Publisher:
release.yml on shayne/viberun
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
viberun-0.3.4-py3-none-any.whl -
Subject digest:
c7f05463fa22ec20adee69621afd9eb131233d49951285d72a2bd3db4080cea8 - Sigstore transparency entry: 843314182
- Sigstore integration time:
-
Permalink:
shayne/viberun@6cf9ca9ad3240b0b3520bc9c883cc0a20945cb40 -
Branch / Tag:
refs/tags/v0.3.4 - Owner: https://github.com/shayne
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6cf9ca9ad3240b0b3520bc9c883cc0a20945cb40 -
Trigger Event:
push
-
Statement type: