Development
This guide covers building and running BarkVisor from source for local
development on macOS. For Linux multi-distro hosts, use
getting-started-linux.md (./scripts/linux-dev.sh
installs packages + Swift and runs smoke tests).
Website (landing + docs): unified Astro app in website/ syncs these Markdown
files into /docs/* (cd website && bun install && bun run dev).
Prerequisites (macOS)
Section titled “Prerequisites (macOS)”| Requirement | Minimum version | Notes |
|---|---|---|
| macOS | 26 | Apple Silicon required (HVF acceleration requires arm64 host for arm64 VMs) |
| Xcode / Swift | Swift 6.x | Project pins Swift 6.2.3 via .swift-version |
| Bun | Latest | JavaScript runtime for the frontend |
| Homebrew | Latest | For installing build and runtime deps |
Installing Build Dependencies
Section titled “Installing Build Dependencies”brew install swiftlint swiftformat- SwiftLint — enforces code style rules (see
.swiftlint.yml). - SwiftFormat — auto-formats Swift source (see
.swiftformat).
Installing Runtime Dependencies
Section titled “Installing Runtime Dependencies”brew install qemu swtpm socket_vmnet- qemu —
qemu-system-aarch64and associated firmware/resources. - swtpm — Software TPM emulator (required for Windows VMs with TPM enabled).
- socket_vmnet — Bridged / vmnet-based networking (optional; NAT works without it).
How BundleResolver Finds Binaries
Section titled “How BundleResolver Finds Binaries”In a release install, binaries live in /usr/local/libexec/barkvisor/ and
QEMU resources in /usr/local/share/barkvisor/qemu/. During development these
do not exist, so BundleResolver falls back through the following search order:
- Installed prefix:
{prefix}/libexec/barkvisor/<name> /opt/homebrew/bin/<name>(Apple Silicon Homebrew)/usr/local/bin/<name>(Intel Homebrew)$PATHlookup viawhich
For Homebrew opt-prefix packages (e.g. socket_vmnet):
- Installed prefix:
{prefix}/libexec/barkvisor/<name> /opt/homebrew/opt/<package>/bin/<name>/usr/local/opt/<package>/bin/<name>
QEMU resources (-L data dir, firmware, keymaps) follow a similar pattern:
- Installed prefix:
{prefix}/share/barkvisor/qemu/<name> /opt/homebrew/share/qemu/<name>/usr/local/share/qemu/<name>
Project Structure
Section titled “Project Structure”The project is organized as 5 Swift Package Manager targets:
Package.swiftSources/ BarkVisorHelperProtocol/ # Shared XPC protocol between app and helper BarkVisorHelper/ # Privileged helper (bridge/vmnet management) BarkVisorCore/ # Core library: models, services, helpers (no Vapor) BarkVisor/ # Vapor HTTP layer: controllers, middleware, routes BarkVisorApp/ # Executable entry point (headless daemon)Tests/ BarkVisorTests/ # Unit and integration testsfrontend/ # Vue 3 + TypeScript SPA (Vite)Target Dependency Graph
Section titled “Target Dependency Graph”BarkVisorHelperProtocol | +-- BarkVisorHelper (executable -- privileged helper daemon) | +-- BarkVisorCore (depends on: GRDB, JWTKit, Yams, NIO) | +-- BarkVisor (depends on: Vapor) | +-- BarkVisorApp (executable -- headless daemon)Key Dependencies
Section titled “Key Dependencies”| Package | Purpose |
|---|---|
| Vapor 4.99+ | HTTP server, WebSocket, routing |
| GRDB 7.0+ | SQLite database (via DatabasePool) |
| JWTKit 5.0+ | JWT authentication |
| Yams 5.0+ | YAML parsing (cloud-init user data) |
| swift-nio 2.65+ | Async networking (VNC/console proxy) |
Building
Section titled “Building”Swift Backend
Section titled “Swift Backend”swift buildOr using the Makefile:
make buildFrontend
Section titled “Frontend”cd frontendbun installbun run build # production build (runs vue-tsc then vite build)The production build output goes into frontend/dist/ and is served by the
Vapor backend as a static SPA (with SPAFallbackMiddleware).
Running
Section titled “Running”Backend
Section titled “Backend”swift run BarkVisorAppThis starts the headless server daemon, which launches the Vapor HTTP server on
0.0.0.0:7777. Open http://localhost:7777 in a browser.
On first run the web UI presents a setup screen where you create the admin account. The data directory is at:
~/Library/Application Support/BarkVisor/This contains the SQLite database (db.sqlite), disk images, firmware state,
logs, and cloud-init data.
Frontend Dev Server
Section titled “Frontend Dev Server”For frontend development with hot-reload:
cd frontendbun installbun run devVite starts on http://localhost:5173 and proxies all /api requests
(including WebSocket upgrades) to the backend at http://localhost:7777:
server: { port: 5173, proxy: { '/api': { target: 'http://localhost:7777', changeOrigin: true, ws: true, }, },}Environment Variables
Section titled “Environment Variables”| Variable | Effect |
|---|---|
BARKVISOR_LOG_DIR | Override the log output directory (default: <dataDir>/logs) |
BARKVISOR_LOG_LEVEL | Minimum log level: debug, info, warn, error, fatal (default: info) |
DISABLE_RATE_LIMIT | Set to 1 to disable login rate limiting (useful for testing) |
Code Quality
Section titled “Code Quality”Linting
Section titled “Linting”make lint # Run SwiftLintSwiftLint is configured in .swiftlint.yml. Key settings:
- Line length warning at 150, error at 200.
- Function body length warning at 80 lines, error at 150.
- Force unwrapping and implicitly unwrapped optionals are flagged.
VMis excluded from type name length rules.id,db,vm,ip,ci,fd,n,i,sare excluded from identifier name length rules.
Formatting
Section titled “Formatting”make format # Auto-format with SwiftFormatmake format-check # Check formatting without modifying filesSwiftFormat is configured in .swiftformat. Key settings:
- 4-space indentation, max line width 150.
- Arguments and parameters wrap before-first.
- Trailing commas are always added.
- File headers are stripped.
Combined Check
Section titled “Combined Check”make check # Runs lint + format-check (suitable for CI)Testing
Section titled “Testing”Unit Tests
Section titled “Unit Tests”swift testOr:
make testThe test suite includes unit tests for services, models, helpers, middleware,
and controller logic. Tests are in Tests/BarkVisorTests/.
Cypress E2E Tests
Section titled “Cypress E2E Tests”End-to-end tests use Cypress against a running BarkVisor instance:
cd frontendbun run cy:open # Interactive Cypress runnerbun run cy:run # Headless Cypress runbun run test:e2e # Alias for cy:runE2E specs cover authentication, dashboard, VM lifecycle, disks, images, networks, registry, settings, navigation, and logs.
Privileged Helper in Debug Builds
Section titled “Privileged Helper in Debug Builds”The XPC privileged helper (BarkVisorHelper) is used for operations that
require root, such as configuring bridged networking via socket_vmnet.
In debug builds, kHelperTeamID is set to "DEVELOPMENT" (defined in
Sources/BarkVisorHelperProtocol/HelperProtocol.swift). The helper skips
code-signing verification in this mode, so you do not need a real Apple
Developer Team ID during development.
For release builds, scripts/build-release.sh injects the real
APPLE_TEAM_ID via sed before compiling:
sed -e 's/kHelperTeamID = "DEVELOPMENT"/kHelperTeamID = "<TEAM_ID>"/' ...