Metadata-Version: 2.4
Name: viberun
Version: 0.3.5
Summary: viberun CLI
License: BSD-3-Clause
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

<p align="center">
  <img src="assets/viberun-logo.png" alt="viberun logo" width="320">
</p>

# 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

```bash
curl -fsSL https://viberun.sh | bash
```

Verify:

```bash
viberun --version
```

Optional overrides (advanced):

```bash
curl -fsSL https://viberun.sh | bash -s -- --nightly
curl -fsSL https://viberun.sh | bash -s -- --dir ~/.local/bin --bin viberun
```

Or with env vars:

```bash
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`):

```bash
viberun bootstrap myhost
```

Optional: set it as your default host (and agent) so you can omit `@host` later:

```bash
viberun config --host myhost --agent codex
```

### 3) Start your first app

```bash
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

```bash
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
```

<details>
<summary>Table of contents</summary>

- [Quick start (end-to-end)](#quick-start-end-to-end)
- [Common commands](#common-commands)
- [Git setup](#git-setup)
- [Development](#development)
- [Architecture](#architecture)
  - [High-level flow](#high-level-flow)
  - [Core components](#core-components)
  - [Session lifecycle](#session-lifecycle)
  - [Bootstrap pipeline](#bootstrap-pipeline)
  - [Networking and ports](#networking-and-ports)
  - [App URLs and proxy](#app-urls-and-proxy)
  - [Snapshots and restore](#snapshots-and-restore)
  - [Host RPC bridge](#host-rpc-bridge)
  - [Configuration and state](#configuration-and-state)
  - [Agents](#agents)
  - [Security model](#security-model)
  - [Wipe (safety)](#wipe-safety)
  - [Repository layout](#repository-layout)
  - [Troubleshooting](#troubleshooting)

</details>

## 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, run `viberun <app> update` once to recreate the container with the agent socket mounted. Then `ssh -T git@github.com` inside the container to verify access.
- **HTTPS (GitHub CLI)**: Run `gh auth login` and choose HTTPS, then `gh auth setup-git`. Verify with `gh 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

```bash
mise install
```

### Build

```bash
mise exec -- go build ./cmd/viberun
mise exec -- go build ./cmd/viberun-server
```

### Run locally

```bash
mise exec -- go run ./cmd/viberun -- --help
mise exec -- go run ./cmd/viberun-server -- --help
```

### Test and vet

```bash
mise exec -- go test ./...
mise exec -- go vet ./...
```

### Container image

```bash
mise run build:image
# fallback: docker build -t viberun .
# proxy image (Caddy + auth):
docker build -f Dockerfile.proxy -t viberun-proxy .
```

### E2E and integration

```bash
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:

```bash
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:

```bash
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: `viberun` CLI on your machine.
- Server: `viberun-server` executed on the host via SSH (no long-running daemon required).
- Container: `viberun-<app>` Docker container built from the `viberun:latest` image.
- 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

1. `viberun <app>` resolves the host (from `@host` or your default config) and runs `viberun-server` over SSH.
2. The server creates the container if needed, or starts it if it already exists.
3. The agent process is attached via `docker exec` inside a tmux session so it persists across disconnects.
4. `viberun` sets up a local port forward so you can open the app on `http://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 `viberun` container image from GHCR (unless using local image mode).
- Downloads and installs the `viberun-server` binary.

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 (default `shayne/viberun`).
- `VIBERUN_SERVER_VERSION`: release tag or `latest`.
- `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 `8080` internally.
- The host port is assigned per app (starting at `8080`) and stored in the host server state.
- `viberun` opens an SSH local forward so `http://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:

```bash
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> url` shows the current URL and access status.
- `viberun <app> url --make-public` or `--require-login` toggles access (default requires login).
- `viberun <app> url --set-domain <domain>` or `--reset-domain` manages custom domains.
- `viberun <app> url --disable` or `--enable` turns the URL off/on.
- `viberun <app> url --open` opens the URL in your browser.
- `viberun users ...` manages login accounts; `viberun <app> users` controls 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> snapshot` creates the next `vN` snapshot.
- `viberun <app> snapshots` lists versions with timestamps.
- `viberun <app> restore <vN|latest>` restores from a snapshot (`latest` picks the highest `vN`).
- `viberun <app> --delete -y` removes 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 `@home` subvolume 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_host`
- `agent_provider`
- `hosts` (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)
- `claude`
- `gemini`
- `ampcode` (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 using `viberun` images, and the proxy container (default `viberun-proxy`).
- All `viberun` images (including the proxy image).
- App data and snapshots under `/var/lib/viberun` (including per-app Btrfs volumes).
- Host RPC sockets in `/tmp/viberun-hostrpc` and `/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 install `btrfs-progs` and ensure sudo access.
- `no host provided and no default host configured`: run `viberun config --host myhost` or use `myapp@host`.
- `container image architecture mismatch`: delete and recreate the app (`viberun <app> --delete -y`).
- `proxy is not configured`: run `viberun proxy setup` (then retry `viberun <app> url`).
