Skip to content

Repository files navigation

Your vibe coded apps and agents need a homescreen
A personalized place for everything you build
Curate your own personal OaSis to suit your vibe

OaSis


OaSis is a self-hosted dashboard that discovers, organizes, and exposes your locally-running apps and AI agents exclusively over your Tailscale network. One Docker container, no accounts, no open ports — your personal homescreen, accessible from any device on your tailnet.

Install the dashboard as a Progressive Web App on any phone or tablet on your tailnet and it launches in full-screen standalone mode, just like a native app. See Installing OaSis as an App for iOS and Android instructions.

Status: This repository is under active development. The CLI, controller, webapp dashboard, and application proxying (iFrame + NGINX gateway) are in place; browser integration tests are planned in upcoming work items.


Contents


How it works

[oasis CLI] ──HTTP──▶ [127.0.0.1:04515 Management API]
│
[Controller (Go)]
╱ │ ╲
[SQLite] [tsnet] [crossplane-go]
│ │
[Tailscale] [NGINX reload]
│ │
[Tailnet browser] [Registered app upstreams]
  • The controller runs inside a single Docker container alongside NGINX and the pre-built Next.js webapp.
  • The management API is bound to 127.0.0.1 only — never reachable from the network.
  • The oasis CLI lives on your host machine and talks to the controller over localhost.
  • The dashboard is served by NGINX over your Tailscale network (tsnet) with automatic TLS — no configuration required.

Prerequisites

To use oasis (end users)

RequirementNotes
DockerDocker Desktop (macOS/Windows) or Docker Engine (Linux)
Tailscale accountFree; needed to generate an auth key

No root/sudo required. On Linux, your user must be in the docker group.

To develop oasis (contributors)

RequirementVersionNotes
Go1.22+go version
Node.js20+node --version
npm10+Bundled with Node.js 20
DockerAny recentRequired for make test-integration and make build-docker
makeAnyStandard on macOS/Linux

User quickstart

Note: The Docker image is not yet published. This section reflects the intended end-user experience once releases are available.

# 1. Install the oasis CLI
brew install [owner]/tap/oasis # macOS / Linux via Homebrew# or: download the binary from GitHub releases and place in /usr/local/bin/oasis# 2. Run first-time setup
oasis init
# → prompts for your Tailscale auth key (get one at login.tailscale.com/admin/settings/keys)# → prompts for a Tailscale hostname (default: oasis)# → pulls the Docker image, starts the container# → prints your dashboard URL when ready# 3. Register your first app# Defaults to --access-type proxy: the app opens in a full-screen iFrame inside the oasis dashboard.# Use --access-type direct to open it in a new browser tab instead.
oasis app add --name "My App" --url http://localhost:3000 --slug myapp
# 4. Check status
oasis status

Your dashboard is now accessible at https://oasis.[tailnet-name].ts.net from any device on your tailnet.


Developer quickstart

# Clone
git clone https://github.com/[owner]/oasis.git
cd oasis
# Install dev tooling (air for live reload, golangci-lint)
make install-tools
# Copy and configure local environment
cp .env.local.example .env.local
# Edit .env.local and fill in TS_AUTHKEY with a dev Tailscale auth key# Start controller (with live reload) + Next.js dev server in parallel
make dev
# Controller: http://127.0.0.1:04515# Webapp: http://localhost:3000

Build

make build # builds ./bin/controller and ./bin/oasis
make build-cli # builds ./bin/oasis only

Version is embedded at build time from git describe --tags --always. Development builds use version=dev.

Test

make test# go test -race ./... + npm test --ci

Lint

make lint # golangci-lint run ./... + tsc --noEmit + next lint

Integration tests

make test-integration # docker compose -f docker-compose.dev.yml up

Integration tests require Docker and a real Tailscale auth key in .env.local. The integration test suite is a stub in the current version — it will be wired up in a future work item.

Docker image

make build-docker # builds the multi-stage image locally (no push)

Repository structure

cmd/
controller/ # Controller binary entry point
oasis/ # CLI binary entry point
internal/
controller/
api/ # Management API handlers (stub)
db/ # SQLite store (stub)
nginx/ # NGINX config generation (stub)
tsnet/ # Tailscale tsnet integration (stub)
cli/
root.go # Cobra root command + global flags
init.go # `oasis init` interactive setup wizard
container.go # start, stop, restart, status, update, logs commands
app.go # `oasis app` subcommand group
settings.go # `oasis settings` subcommand group
db.go # `oasis db` subcommand group
config/ # CLI config (~/.oasis/config.json) load/save
client/ # HTTP client for the management API
docker/ # Docker CLI wrapper (pull, run, start, stop, logs, …)
table/ # Output formatting: tables, key/value lists, spinner
webapp/ # Next.js App Router (static export)
app/ # Root page, layout, and global styles
components/ # AppIcon, AppProxyView, BottomNav, EmptyState, HomescreenLayout, TimeOfDayBackground + shadcn/ui primitives
lib/ # Typed API fetch helpers (api.ts) and shared utilities
__tests__/ # Jest unit tests
.github/workflows/
ci.yml # Lint + test + build on every push/PR
release.yml # Multi-arch Docker image + CLI binaries on semver tag
Dockerfile # Multi-stage: node:20-alpine → golang:1.22-alpine → debian:bookworm-slim
Makefile # All build/dev/test/lint targets
.env.local.example # Canonical list of environment variables
aspec/ # Living design specification — source of truth

Build targets

TargetDescription
make install-toolsInstall air (live reload) and golangci-lint into $GOPATH/bin
make devStart controller with live reload + Next.js dev server (parallel)
make buildBuild webapp static export + ./bin/controller + ./bin/oasis
make build-webappBuild the Next.js static export to dist/webapp/ only
make build-cliBuild ./bin/oasis only
make generate-iconsRegenerate PWA icon PNGs from webapp/public/icons/icon.svg
make testGo unit tests (race detector) + Jest unit tests
make lintgolangci-lint + TypeScript type check + Next.js lint
make test-integrationFull integration test suite via Docker Compose
make build-dockerBuild Docker image locally (runs generate-icons first)

Environment variables

All variables are documented in .env.local.example. Copy that file to .env.local for local development — it is git-ignored and must never be committed.

VariableDefaultDescription
TS_AUTHKEYTailscale auth key (first start only; not needed after tsnet state is persisted)
OASIS_MGMT_PORT04515Management API port (published loopback-only: 127.0.0.1:PORT)
OASIS_HOSTNAMEoasisTailscale node hostname
OASIS_DB_PATH/data/db/oasis.dbSQLite database path inside the container
OASIS_TS_STATE_DIR/data/ts-stateTailscale tsnet state directory inside the container
OASIS_LOG_LEVELinfoLog verbosity: info | debug | warn | error
NEXT_PUBLIC_API_BASE_URL`` (same origin)Base URL for controller API calls from the webapp. Leave empty in production (NGINX serves both); set to http://localhost:04515 for local dev.
OASIS_AGENT_RUNS_DIR/data/agent-runsBase directory for agent run work directories (one sub-dir per run ID, retained for debugging)
OASIS_CLAUDE_BIN`` (resolve from $PATH)Override path to the claude CLI binary; useful for testing with a fake binary
OASIS_CHAT_TIMEOUT120sTimeout for synchronous chat invocations (POST /api/v1/chat/messages); Go duration string

Contributing

Branch workflow

git checkout -b feat/your-feature
# make changes
git commit -m "feat: add your feature"
git push origin feat/your-feature
# open a pull request — CI must pass before merge# PRs are squash-merged to keep history clean

Commit convention

This project uses Conventional Commits for automated changelog generation:

PrefixWhen to use
feat:New user-facing feature
fix:Bug fix
chore:Tooling, deps, config — no production code change
docs:Documentation only
test:Tests only
refactor:Code restructure with no behaviour change

CI pipeline

Every push and pull request runs:

  1. lint-gogolangci-lint run ./... + go vet ./...
  2. lint-webtsc --noEmit + next lint
  3. test-gogo test -race ./... with coverage report
  4. test-webjest --ci --coverage
  5. build — Go binaries (static linkage verified) + Next.js static export + Docker image

All jobs must pass before a PR can be merged.

Go module path

The module path is github.com/[owner]/oasis — update [owner] in go.mod to the actual GitHub org/user before the first tagged release.

Security invariants

These must never be broken:

  • The management API binds exclusively to 127.0.0.1 — asserted in unit tests
  • TS_AUTHKEY is never logged or returned in API responses
  • All container processes run as uid 1000 (non-root)
  • Go binaries are compiled with CGO_ENABLED=0 (static, no libc dependency)
  • NGINX configuration is reloaded with SIGHUP — never a process restart

Built with Go, Next.js, Tailscale, and good vibes.

About

A cozy home for your vibe coded apps and personal AI agents

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

Generated from prettysmartdev/aspec