Yaver
P2P dev-machine MCP for phone-driven coding agents: hot reload, builds, deploys.
Ask AI about Yaver
Powered by Claude Β· Grounded in docs
I know everything about Yaver. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
Yaver
Docs: CI setup Β· Test SDK Β· Runtime Control Plane
Build apps and game loops from your phone. Keep the backend and build machine local until you decide otherwise.
Using an AI agent? If a coding agent (Claude Code, Codex, Cursor, Aider, β¦) is reading this because the human asked it to "install yaver" or "set up yaver", stop here and fetch https://yaver.io/llms.txt β that file is the canonical, machine-readable install + configure guide. It covers headless / WSL / SSH, the resumable device-code flow, and exactly what to surface back to the human. Do not scrape the rest of this README as a substitute.
Yaver's short-term product target is phone-first app and backend creation, then promotion to your own dev machine, then optional promotion to Yaver Cloud. The core claim is narrow on purpose:
phone sandbox -> your dev machine -> Yaver Cloud
What is real in the repo today:
- Hermes reload from Linux, WSL, macOS, or a remote host into the Yaver mobile app
- local phone-project sandboxing with SQLite-backed data, schema, auth personas, seed data, and CRUD
- portable export/import/push of a phone project to another
yaver serveagent - remote dev-box flows where the box is mostly web UI + backend, runs Claude Code / Codex / other coding agents, and streams run/test output back to mobile
- MCP and CLI surfaces for phone project export, import, and push
- local-first runtime API for third-party apps using per-project tokens
- npm-based install and upgrade via
npm install -g yaver-cliacross macOS, Linux, and WSL - Unity feedback/build/test/relaunch groundwork for mobile and desktop projects
What is still incomplete:
- the default one-tap monorepo scaffold for phone-created projects
- more polish on the AI prompt-to-project scaffold
- a fully proven end-to-end App Store / TestFlight release loop from this machine
The Clear Story
Yaver's primary loop is:
- Start on the phone.
- Vibe-code the app and backend from the phone.
- Run the first backend tier in the phone sandbox.
- Grow the same project onto your dev machine, your own server, or Yaver Cloud.
- Keep Supabase, Convex, Postgres, Turso, Firebase, and similar systems as escape hatches, not the default destination.
What is first-class today:
- Hermes reload from Linux / WSL / remote host to iPhone or Android through the Yaver mobile app
- Mobile-first backend sandbox with schema, auth personas, seed data, CRUD, and local persistence
- Promotion to your own hardware via
yaver serveon a Mac, Linux box, Pi, VPS, or other reachable machine - Remote coding-box workflows where your machine is just the app/backend box, Yaver runs the app or tests there, and the phone watches the live stream
- Promotion to Yaver Cloud via the same portable bundle and the same
yaver servebinary - Containerized export for running the promoted backend on your own cloud with Docker
- Escape routes to systems like Supabase and Convex as secondary trust signals
What is not fully finished yet:
- Phone-first monorepo scaffolding as the default one-tap
initpath - Prompt scaffold quality polish for the phone-created full-stack starter
The headline path is Yaver-native:
phone sandbox -> your dev machine / your cloud / Yaver Cloud
Everything else is there so the user knows they can leave later.
For a WSL-based developer, that means:
- Run
yaver serveor the Go agent tooling on WSL/Linux. - Build the Hermes bundle on that host.
- Open the app inside the Yaver mobile app on the phone.
- Use native-install paths only when you actually need a full store/native build.
The Three Pieces of Yaver
Yaver is built for solo developers and small teams who ship from anywhere. It has three distinct pieces:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β π± MOBILE APP (yaver.io) π§ AGENT (yaver) β
β App Store / Play Store npm install -g yaver-cli β
β or brew install yaver β
β β
β Remote control for everything. The brain on your dev machine. β
β Send tasks to AI agents, test apps on Runs AI agents (Claude Code, β
β real hardware, hot reload, visual QA. Codex, Aider). Serves P2P β
β Native container for RN apps (not WebView). connections, manages builds, β
β Works from beach, coffee shop, anywhere. pushes RN bundles to phones, β
β MCP server with 473 tools. β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β π FEEDBACK SDK β
β yaver feedback setup β
β β
β Embed in YOUR app during dev. Shake to report bugs with screenshots + β
β voice. Black box flight recorder streams all events to your AI agent. β
β React Native, Flutter, Web. β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
You might use:
- Just the mobile app + agent β control AI agents from your phone, hot reload any framework
- Add the Feedback SDK β embed a debug console in your app, shake to report bugs to your AI agent. If you pair a guest app with Yaver, let the Feedback SDK own haptics; do not keep a second app-level
expo-hapticslayer active on top. - All three together β the full loop: code on machine, push to device, test, report bugs, AI fixes, repeat
Yaver Protocol v1 β never feel disconnected
The agent is the producer; the mobile app and dashboard are consumers. They communicate over an SSE channel at /dev/events using a structured protocol with three guarantees:
- Real progress, not fake. The agent regex-parses Metro / Expo / Hermesc stdout (
Bundling 67% (1247/2390)) into structuredprogressevents withpct,done,total,currentFile,etaMs, and aprogressSrcofexact/heuristic/unknown. Consumer renders an indeterminate spinner forunknown; never fakes a percentage. - Snapshots every 5 seconds.
snapshotevents embed the full picture: every active topic's phase, last progress, recent log tail. A reconnecting consumer reads ONE snapshot and is fully caught up. - Liveness contract decoupled from compile state. Consumer tracks time-since-last-byte separately from compile progress.
< 6s = live Β· 6β15s = syncing Β· 15β60s = reconnecting Β· > 60s = lost. Slow compiles never look like "lost" connections.
Topics: dev/start Β· webview/build Β· hermes/compile Β· bundle/push. Phases per topic and full event schema in docs/yaver-protocol.md.
AI + IoT Fix Architecture
Yaver is also the control-plane shape for an AI-driven IoT repair loop.
The architecture we are designing is:
mobile orchestrator -> cloud brain -> LLM coordinator -> c-agent runtime on device
The simple version is:
LLM writes code -> toolchain compiles it -> firmware already has c-agent -> device dynamically loads/runs it -> result comes back -> loop iterates
Each layer has one job:
- Mobile orchestrator: operator UI, incident intake, approvals, live status
- Cloud brain: session coordination, audit trail, retrieval, module registry, signing pipeline
- LLM coordinator: decides which probe or fix should run next for this incident
- c-agent runtime: small device-side runtime that verifies artifacts, binds capabilities, executes bounded code, and streams results back
The important distinction is that the LLM is not the runtime. The model writes the next probe or fix. The runtime is what makes that code actually runnable on the device.
That matters for real IoT repair cases. A Klipper printer, OpenWrt router, PX4 drone, or robotics host rarely fails in a way that a static predefined tool list fully covers. The useful system is one that can author a small incident-specific probe or fix, compile it, ship it, run it safely on the device, inspect the result, and iterate.
An important hardware/firmware design rule falls out of that: AI-fixable components should be able to enter a bounded stuck or degraded mode instead of crashing the whole device. If a dependency wedges, the component should quiesce, preserve enough state, report that it is waiting for replacement, and resume when a new module is inserted and validated. Good firmware architecture is mandatory. That is the difference between a system the brain can iteratively repair and a system that just hard-resets on every subsystem fault.
That loop looks like:
phone reports issue -> brain plans -> LLM writes bounded probe/fix -> build/sign -> c-agent verifies/runs -> telemetry returns -> LLM writes next attempt -> repeat until fixed or budget hit
This is the motivation behind the embedded/c-agent/ work in this repo and the architecture docs under docs/c-agent-*.md.
Key Features
- Push to Device β Real-device testing in ~4 seconds. No TestFlight. 40+ native modules.
- Visual QA Loop β Shake to report. AI sees screenshot, writes fix, hot reloads.
- Autonomous Testing β Agent navigates screens, catches crashes, fixes, repeats.
- P2P Encrypted β Code flows directly between devices. No cloud.
- Any AI Agent β Claude Code, Codex, Aider, Ollama, Goose, Amp, or any CLI tool.
- Hot Reload β Expo, Flutter, Vite, Next.js over P2P.
- 473 MCP Tools β Docker, K8s, git, CI/CD, databases.
- Feedback SDKs β Debug console for React Native, Flutter, Web.
- Unity Feedback SDK β In-game overlay, feedback/crash capture, content refresh, Unity test/build/relaunch hooks.
- Session Transfer β Move AI sessions between machines.
- Chained Tasks β Queue a whole feature: "build landing page, add Stripe, deploy." Tasks execute sequentially, next starts when previous succeeds.
- Auto-Retry β Failed task? Agent retries with error context. Only pings you after 3 failures.
- Ship It Button β One tap to deploy. Agent detects your project (Cloudflare, Vercel, TestFlight, Play Store, Fly.io, etc.) and ships.
- Morning Summary β Daily digest at 9am: "3 tasks done, landing page live, 2 tests failing." Via Telegram, Discord, Slack, or email.
- Live Terminal Stream β Watch Claude Code work in real-time from your phone via SSE. Full terminal output, not just status updates.
- Set-and-Forget Autodev β
yaver autodev <project>forks itself as a detached, session-leader child so the kick loop survives terminal close, ssh disconnect, or laptop lid. Kicks fire on a timer (5 min in lite, 30 s in burst), refill ideas when the checklist empties (--auto-ideas, default 999), optionally use a hardening preset (--harden security|memory|perf|quality|all), pin a roof theme (--prompt), work on a dedicated branch (--auto-branch), and ship to every shippable surface at the end (--deploy autocovers TestFlight, Play Store, Convex, Vercel). Re-attach the live tail any time withyaver stream autodev:<loop>. - Autoinit (cached project context) β
yaver autoinit <project>writes a projectinit.md(stack, layout, conventions, build/test/deploy commands, recent direction) that every later autodev / autoideas / autotest kick reads as cached context, so Claude doesn't re-grep the repo from scratch every kick. Each successful run auto-appends to the file's history block so the next session knows what was just shipped. Available as CLI, HTTP (POST /autoinit/start,GET /autoinit/status), and MCP (autoinit_start,autoinit_status). - Autoideas (overnight idea generator) β
yaver autoideas <project>runs a long-lived loop that asks the AI for fresh single-PR-sized improvement ideas every tick and appends them as- [ ] <title>lines toideas.md. Mobile / web shows them as checkboxes; pick the ones you want and the daemon fires anautodevrun with the curated subset as--remained. Generation continues in parallel with implementation. Same flag set as autodev (--hours,--lite/--heavy,--prompt,--harden,--engine,--hybrid). - Live Chat Stream (terminal + mobile + web) β autodev publishes structured events (
yaver_say,runner_action,runner_text,runner_result) to/streams/autodev:<loop>so any client renders the run as a chat: yaver's voice on one side, the AI's on the other, tool uses inline. Generic across runners (Claude / Codex / Aider / Ollama). Mobile Auto Dev tab has a Chat section; CLI usesyaver stream <name>for ANSI-colored bubbles. - Always Native, Never WebView β React Native apps always load via Hermes bytecode into a native bridge with TurboModules + Fabric. WebView is never used for app loading.
- Task Scheduling β Cron-like scheduling.
- Notifications β Telegram, Discord, Slack, Teams, PagerDuty, Opsgenie, Linear, Jira, email.
- CI/CD Webhooks β GitHub Actions, GitLab CI triggers.
- Git Providers β Browse and clone repos from phone.
- SDKs β Go, Python, JS/TS, Flutter/Dart, C.
Vibe Coding from Anywhere
Built for the solo developer who ships from a beach in Thailand. Dump tasks from your phone, let your machine do the work, check results over coffee.
Morning at the beach:
1. Open Yaver β Queue 5 tasks: "add dark mode", "fix login bug",
"write payment API", "add validation", "deploy to Cloudflare"
2. Agent chains them β each starts when the previous succeeds
3. If one fails, agent retries with the error context (up to 3x)
4. You get a push: "4/5 done, payment API retry 2/3 in progress"
Lunchtime:
5. Check the Summary β "4 tasks done ($0.32), 1 running"
6. Open the live terminal stream β watch Claude Code typing in real-time
7. Tap "Ship It" β one tap, agent deploys to Cloudflare Workers
Next morning:
8. Morning summary notification: "5 tasks completed, site live at myapp.com"
Chained Tasks (queue a whole feature)
# From the mobile app or API:
POST /chain
{
"tasks": [
{ "title": "Build a landing page with pricing section" },
{ "title": "Add Stripe checkout for $10/mo plan" },
{ "title": "Write tests for the payment flow" },
{ "title": "Deploy to Cloudflare Workers" }
],
"autoRetry": true
}
# β First task starts immediately. Each subsequent task starts when the previous completes.
# β If any task fails, it auto-retries with error context (up to 3x).
# β Chain stops if a task fails all retries.
Ship It (one-tap deploy)
The agent auto-detects your project type and offers the right deploy target:
| Detected | Deploy Target | Command |
|---|---|---|
wrangler.toml | Cloudflare Workers | npm run deploy |
vercel.json | Vercel | npx vercel --prod |
netlify.toml | Netlify | npx netlify deploy --prod |
ios/ + deploy script | TestFlight | scripts/deploy-testflight.sh |
android/ + deploy script | Google Play | scripts/deploy-playstore.sh |
convex/ | Convex | npx convex deploy |
firebase.json | Firebase | npx firebase deploy |
fly.toml | Fly.io | fly deploy |
docker-compose.yml | Docker Compose | docker compose up -d --build |
iOS TestFlight is LOCAL-ONLY β never run from CI
Don't add a CI workflow that uploads to TestFlight. It will fail on
provisioning every time, even when the local Mac uploads cleanly. CI runners
don't carry the developer-account-registered iPhone UDIDs that the
provisioning profile bakes in, so xcodebuild errors out at archive time with
Device "<UDID>" isn't registered in your developer account /
No profiles for 'io.yaver.mobile' were found. We tried and it kept burning
release minutes for no shipped build.
Always ship iOS from this Mac with the existing local script:
export APP_STORE_KEY_PATH="<your-apple-key-path>"
export APP_STORE_KEY_ID="<your-apple-key-id>"
export APP_STORE_KEY_ISSUER="<your-issuer-uuid>"
export APPLE_TEAM_ID="<your-apple-team-id>"
./scripts/deploy-testflight.sh
The script auto-bumps CFBundleVersion, archives, and uploads to TestFlight
in one step (~25β30 min). Daily TestFlight upload cap is ~15β20 builds β
plenty of headroom for normal iteration. Android Play Store deploys can run
from CI (and currently from the same Mac via scripts/deploy-playstore.sh)
since the keystore lives in the gitignored keys/ dir / GH ANDROID_KEYSTORE
secret rather than being device-account-bound.
Unity
Yaver now also has a Unity lane.
The Unity contract is:
- feedback SDK inside the Unity project
- in-game overlay
- screenshots, logs, crashes, black-box capture
- vibing from inside the game
- content refresh / scene reload / redeploy ladder
- Unity EditMode/PlayMode tests on the agent machine
- desktop build/relaunch flow for self-hosted iteration
Read more:
Morning Summary
Daily digest at 9am via all configured notification channels:
βοΈ Morning Summary
π 5 tasks: 4 completed, 1 failed ($0.47)
β
Build landing page with pricing (34s)
β
Add Stripe checkout (89s)
β
Write payment tests (22s)
β
Deploy to Cloudflare (15s)
β Add dark mode (failed after 3 retries)
Always Native, Never WebView
React Native apps pushed to the Yaver phone app always load natively β never in a WebView. The pipeline:
- Bundle: Metro bundles your JS into a single file
- Compile:
hermesccompiles JS β Hermes bytecode (HBC, version 96, from RN 0.81.5) - Validate: Both CLI and phone validate HBC magic (
0x1F1903C1) and BC version match - Load: Phone creates a native bridge via
ExpoReactNativeFactorywith full New Architecture support - Run: Your app runs with TurboModules, Fabric, and JSI β same as if built with Xcode
The safeReloadBridge sequence invalidates the old bridge, waits for HadesGC cleanup (up to 3s weak-reference poll), then creates a fresh bridge. This prevents SIGABRT crashes from GC touching freed memory.
Why this matters: WebView-based "containers" (like some dev tools) can't access native modules, have different performance characteristics, and break any app using TurboModuleRegistry.getEnforcing(). Yaver's native bridge gives your app the same runtime as a production build.
Full Pipeline from Anywhere
Developer at the beach? No problem.
1. Open Yaver on your phone
2. Switch to your repo: "switch to my-flutter-app"
3. Chat with your AI agent β it writes code on your home machine
4. Build: yaver build flutter apk
5. Test: yaver test unit
6. Deploy: artifact transfers P2P to your phone β tap to install
Or run the full pipeline:
yaver pipeline --test --deploy p2p
Skip GitHub Actions. Skip TestFlight queues. Your build goes straight to your phone.
Key capabilities:
- Repo switching β
yaver repo switch my-appauto-discovers git repos under~/and changes the agent's working directory. No manual path typing. - Auto-detect testing β
yaver test unitdetects your framework (Flutter, Jest, pytest, Go test, Cargo, XCTest, Espresso, Playwright, Cypress, Maestro) and runs the right command. Pass/fail counts stream to your phone. - yaver-test-sdk β Embedded E2E test runner that replaces Playwright + Percy + axe-core. Drop YAML specs under
yaver-tests/, runyaver test run, and every test executes on your own hardware for $0/mo. Seedocs/yaver-test-sdk.md. - Full pipeline β
yaver pipeline --test --deploy p2pbuilds, tests, and deploys in one command. Stops on test failure by default. - Platform-aware builds β When you request a build from your phone, the agent knows your platform (iOS or Android) and builds the right artifact (APK/AAB for Android, IPA for iOS).
- Expo support β
yaver build expo-androidandyaver build expo-iosfor Expo-managed projects. Runseas buildorexpo prebuild+ native build depending on your setup. - Auto vault sync β When your phone connects to the agent, keys and signing credentials from the P2P encrypted vault sync automatically. No manual key management on each connect.
- Store uploads β
yaver build push testflightandyaver build push playstoreupload directly to app stores. Credentials stay in the vault.
Self-Host a Relay Server
Install a relay on any VPS with one command:
curl -fsSL https://yaver.io/install-relay.sh | sudo bash -s -- \
--domain relay.example.com \
--password your-secret
This installs Docker, deploys the relay, sets up nginx + Let's Encrypt SSL, and configures auto-updates. The relay is a pass-through proxy β it never stores your data. All connections are encrypted via QUIC (TLS 1.3).
How It Works
βββββββββββββββ HTTP ββββββββββββββββ QUIC tunnel ββββββββββββββββ
β Mobile App βββββββββββββββββββΊβ Relay Server βββββββββββββββββββββ Desktop Agentβ
β (React Native) short-lived β (optional) β persistent β (Go CLI) β
β Wi-Fi/5G β HTTP requests β public IP β outbound conn β behind NAT β
ββββββββ¬βββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ
β β β
β Auth only β Platform config β Register device
βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Convex Backend β
β Auth + Peer Discovery + Platform Config (relay server list) β
β Apple / Google / Microsoft Sign-In β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
No code, task data, or AI output ever touches our servers. The relay is a pass-through proxy. When you're on the same network, traffic goes direct.
Quick Start
# Install
npm install -g yaver-cli
# Upgrade later
npm install -g yaver-cli@latest
# Sign in β GUI machine opens a browser, headless (Pi / VPS / SSH-only / Docker) uses --headless
yaver auth # opens browser automatically
yaver auth --headless # prints a URL + short code you approve from your phone
# `yaver auth` starts the agent automatically if needed
#
# Supported sign-in providers (all 6 linkable to the same account):
# Google Β· Apple Β· Microsoft/O365 Β· GitHub Β· GitLab Β· email/password
# See https://yaver.io/download#headless-auth for the full flow.
# Adopt a project (one-time, ~3 min) β caches stack/layout/conventions into init.md
cd ~/code/my-project
yaver autoinit my-project
# Generate ideas overnight (long-lived, detached, survives terminal close)
yaver autoideas my-project --hours 8 --engine codex
# Pick ideas later via mobile / web (checkboxes) β triggers autodev on the picks
# Or go straight to autodev β picks the next remained.md item every kick
yaver autodev my-project --hours 8 --model sonnet # cheap default
yaver autodev my-project --hours 1 --model opus --max-iterations 1 # high-stakes one-shot
yaver autodev my-project --planner claude:opus --implementer codex # hybrid: premium plan, cheap impl
# Watch the live chat from any terminal (or the mobile Auto Dev tab)
yaver stream autodev:my-project-autodev
Headless machines (Mac mini upstairs, Hetzner VPS, Linux box over SSH)
You don't need a browser on the headless machine. Pick one:
# Option A β fresh OAuth via QR (Apple / GitHub / GitLab / Google / Microsoft)
yaver auth --headless
# β prints a QR code pointing at yaver.io/auth/device
# β scan it with your phone camera, sign in with whatever provider,
# the headless agent polls and receives the token.
# Option B β copy an existing signed-in token over the P2P relay
# (fastest path β no OAuth dance at all)
yaver auth pair
# β prints a 6-char pairing code + QR code.
# On a machine that's already signed in (your laptop), run:
yaver auth send <PAIR-CODE> <target-url-from-the-qr>
# Or scan the QR from the Yaver mobile app β More β Pair device.
Both paths work the same for Apple, GitHub, GitLab, Google, and
Microsoft β the web sign-in page at yaver.io/auth/device accepts all
five and hands
the resulting token back through the device-code flow.
Headless reachability defaults:
- Linux and macOS now block OS sleep while
yaver serveis running - WSL cannot block Windows host sleep from inside the distro
- real pre-login macOS boot requires one extra privileged step:
sudo yaver serve --install-launchd-daemon - WSL reboot recovery is best-effort: Yaver installs a shell helper and prefers a Windows Scheduled Task when available, but the Windows host still needs sleep disabled for unattended remote use
For a persistent Hetzner box that should stay installed as both your own owner-authenticated machine and a shared CI/guest host, see docs/hetzner-shared-owner-runbook.md. For the default security/functionality posture behind fresh installs, see docs/default-install-protection.md.
All Installation Methods
| Method | Command |
|---|---|
| npm | npm install -g yaver-cli |
| Upgrade | npm install -g yaver-cli@latest |
| What it installs | yaver plus the bundled push/dev bootstrap from the yaver-cli npm package |
Default Protection / Functionality Balance
New installs should now be both usable and protected by default.
- Yaver does not need root for normal daily use.
yaver auth,yaver serve, hot reload, vibe coding, feedback, and most build/deploy flows are designed to run as a normal user. - Root is only needed for machine-level setup: installing OS packages, writing system services, changing Linux sysctls, enabling Docker for a service user, or provisioning a fresh remote box.
- The Yaver agent stays host-native. That keeps hot reload, dev servers, Xcode, Gradle, Hermes, Expo/EAS, deploy flows, relay, and device bridging attached to the real machine.
- Owner coding flows stay host-native too. Yaver's three first-class runners (
claude,codex,opencode) are not blindly forced into Yaver's Docker sandbox for normal owner tasks, because that breaks real auth/toolchain access on many machines. - Guest and feedback-only tasks are the place where hard isolation matters most. Yaver keeps the guest restrictions there and can additionally containerize those tasks when Docker isolation is enabled.
- On Linux, Yaver now prefers explicit blocked state over false readiness. If a runner is installed but the host still blocks its own sandbox prerequisites, the UI marks that runner as blocked instead of letting tasks hang and fail later.
Install-path expectations:
npm install -g yaver-clinow does a best-effort Linux bootstrap for runner safety. When the install has root privileges on Debian/Ubuntu, it enables the required user-namespace sysctls and installsbubblewrap/uidmapwhen those packages are missing.- Managed cloud / Hetzner bootstrap paths now also ensure Docker is enabled, Linux user-namespace prerequisites are set, and the
yaverservice user is added to thedockergroup in service-user deployments. - If a lean install does not have enough privilege to harden the host, Yaver leaves the machine unchanged and surfaces blocked runners clearly instead of pretending they are healthy.
That split is deliberate: protect untrusted guest execution without breaking the main Yaver loop of vibe coding, hot reload, build, and deploy.
Protecting A Remote Box From Destructive Agent Actions
Yaver has multiple layers here, but the boundary matters:
- The command sandbox is enabled by default and blocks known-destructive commands such as recursive deletion of critical system paths, privilege escalation, raw disk writes, piping remote content into a shell, and similar host-compromise patterns.
- The sandbox also specifically refuses recursive deletion of common workspace/code roots like
/Users,/home,$HOME, and common home subdirectories such as~/Workspace,~/Projects,~/Code,.ssh,.aws, and.yaver. - Guest and feedback-only tasks can run in a Docker container instead of on the host. In that mode the task only sees the mounted project directory, selected env vars, and optional extra mounts that pass Yaver's mount validation.
- Container mounts are validated so the sandbox cannot silently re-expose
/,/home,/Users,/etc, or the Docker socket back into the task container.
What this does not mean:
- Yaver does not try to stop an owner-authorized host task from editing the current project. That would break legitimate coding work.
- If you want the strongest protection for a remote shared box, prefer
--containerize-guestsand run untrusted work as guest/feedback sessions rather than as the owner. - If you want protection against accidental repo loss even for owner tasks, use normal engineering safety nets too: git, remote origin, snapshots, or a dedicated throwaway worktree/clone.
Raspberry Pi 5 dev-node image
The download page also exposes a Raspberry Pi 5 dev-node image through the same Convex-backed public artifact pipeline as the CLI assets. The image build itself is Linux-native; from macOS use ./scripts/build-pi-image.sh --docker once Docker is running, or let the pi-image/vX.Y.Z GitHub workflow build and publish it. The Pi image is a hybrid appliance: it bakes in the OS image, the yaver binary, first-boot provisioning, cloud-init, and systemd services, then uses first boot to install the heavier dev/backend stack (claude-code, codex, opencode, TDD tools, sqlite3, vercel, convex, PostgreSQL, Redis, Supabase, MQTT).
Always-Up Mode (Boots Without Auth)
yaver serve is designed to start and stay reachable even on a brand-new install with no token. The HTTP server comes up in bootstrap mode the moment you run it for the first time, and on the primary always-on targets it also registers itself with the OS auto-start system.
Primary always-on targets:
- macOS via LaunchAgent by default, or LaunchDaemon for real headless pre-login boot
- Linux via systemd user service + linger
- Windows via Scheduled Task
WSL support is different:
- WSL is supported for the React Native / Hermes daily loop and headless auth
- WSL is not the same as native Linux for reboot persistence
- Yaver does not install a native systemd auto-start service inside WSL
- Yaver installs a WSL startup helper and prefers a Windows Scheduled Task when available
- WSL cannot stop the Windows host from sleeping; unattended remote use still requires Windows power settings and ideally Tailscale on Windows itself
- native Linux and macOS still have the stronger always-on path
# Brand-new install. No `yaver auth` needed yet.
yaver serve
# β Yaver agent started in bootstrap mode (PID β¦, port 18080).
# β Registered as macOS LaunchAgent (will auto-start after login).
#
# This machine has no auth token yet. The agent is up and waiting.
# Open the Yaver mobile app (already signed in) on the same Wi-Fi β
# the box will appear as 'needs auth', tap it to pair.
yaver status reflects the bootstrap state instead of bailing:
Yaver: v1.85.0
Auth: β not signed in
Agent: β running (bootstrap mode, port 18080)
Host: mac-mini.local
Mode: bootstrap β waiting for a phone to pair
Auto-start: β installed (will run on login/boot)
The bootstrap HTTP surface only mounts the pairing/recovery endpoints needed to receive a token β /health, /info, /auth/pair/{info,session,submit,encrypted}, and /auth/recover. Everything else (tasks, vault, exec, dev server) is gated behind a successful pairing.
Two Ways to Pair From the Mobile App
| Path | When | How |
|---|---|---|
| LAN beacon | Box and phone on the same Wi-Fi | Bootstrap mode broadcasts a UDP beacon every 3s. The mobile app's beacon listener picks it up automatically and shows it in More β Pair device with a one-tap "adopt this machine" button. |
| Remote re-auth (host-only) | Box is reachable remotely and your phone or web dashboard already knows it | The caller POSTs to /auth/recover with your Convex Bearer token. The agent calls convex /devices/owner-by-hardware with its hardware fingerprint. If Convex says you're the registered owner, the recovery flow proceeds. No pre-shared secret to remember β your Convex identity IS the host check. |
The mobile app automatically picks the right path based on whether the device is in your device list. Guests can never trigger the recovery flow on a host machine, even if they know the relay URL β the host check happens server-side in Convex against the original userId that registered the hardware fingerprint.
By default, /auth/recover stays reachable on the main HTTP listener. If you want the stricter posture, enable private-only recovery:
yaver config set require-private-recovery true
# or one-off for this serve process
yaver serve --recovery-policy=private
In private-only mode, direct public HTTP hits to /auth/recover are rejected. Mobile can still recover over LAN or Tailscale; the web dashboard needs a private relay or an HTTPS Cloudflare Tunnel.
Survives Reboots
The first yaver serve writes the OS-native auto-start descriptor:
| OS | What gets installed |
|---|---|
| macOS | Default: ~/Library/LaunchAgents/io.yaver.agent.plist (RunAtLoad + KeepAlive, starts after login). For a real headless Mac mini that must boot before login: sudo yaver serve --install-launchd-daemon, which installs /Library/LaunchDaemons/io.yaver.agent.plist. |
| Linux | ~/.config/systemd/user/yaver.service + loginctl enable-linger so the unit runs without an interactive login. |
| WSL | No native systemd service. Yaver installs a WSL startup helper and prefers a Windows Scheduled Task when available; Windows host sleep still has to be handled in Windows settings. |
| Windows | A scheduled task that fires on user login. |
After the first install the agent comes back automatically on native Linux and Windows, and on macOS after login via the default LaunchAgent. For a truly headless macOS box that must come back before login, install the LaunchDaemon once. On WSL, keep the expectation narrower: the daily dev flow is supported and Yaver can install the helper + Windows-login path, but native Linux/macOS still provide the stronger always-on behavior.
Visual Feedback Loop
Test your build on your real device, record bugs visually, and the AI agent fixes them.
You test the app β Record screen + voice β AI agent sees the recording β Fixes the bugs β Rebuilds β Repeat
Three runtime modes (user selects at runtime from within their app):
| Mode | What happens | Best for |
|---|---|---|
| Full Interactive | Screen + voice stream live to agent. Agent's vision model detects bugs in real-time. Hot reload pushes fixes as you speak. Say "make this bigger" and it happens. | Active development, quick iterations |
| Semi Interactive | Screen + voice stream live. Agent comments on what it sees but doesn't auto-fix. Say "fix it now" or "keep in mind for later". | Code review, discussion, QA |
| Post Mode | Record everything offline. No streaming. Compress and submit when done. Agent processes the full session afterwards. | Slow connections, detailed QA, batch reports |
Agent Commentary Levels (0-10): Controls how proactive the agent is. Level 0 = silent. Level 5 = comments on obvious issues. Level 10 = comments on everything it sees (layout, performance, accessibility). Like pair programming where the AI watches over your shoulder.
Feedback SDKs
Embed in your app during development. The SDK provides device discovery, connection UI, screen recording, voice annotation, and P2P upload β all in a single package. Disabled automatically in production builds.
Preferred install flow:
npm install -g yaver-cli
On Linux, the global install now does a best-effort bootstrap for hosted coding
agents too: if it has root, it enables the user-namespace sysctls Codex needs
and installs bubblewrap/uidmap when they're missing. If it does not have
enough privilege, Yaver leaves the machine unchanged and marks blocked runners
as blocked instead of pretending they're ready.
# Then, inside the project you want to wire up:
yaver feedback setup
# Or be explicit:
yaver sdk add feedback --platform web
yaver sdk add feedback --platform react-native
yaver sdk add feedback --platform flutter
Manual fallback:
# Web (any framework: React, Vue, Svelte, vanilla JS)
npm install yaver-feedback-web
# React Native
npm install yaver-feedback-react-native
# Flutter
flutter pub add yaver_feedback
Quick start (Web):
import { YaverFeedback } from 'yaver-feedback-web';
if (process.env.NODE_ENV === 'development') {
YaverFeedback.init({ trigger: 'floating-button' });
// That's it. A "Y" button appears. Click to record bugs.
// Auto-discovers your Yaver agent on the LAN.
}
Quick start (React Native, 0.5+):
import { YaverFeedback, FeedbackModal } from 'yaver-feedback-react-native';
// Zero-config: no agentUrl, no authToken needed.
// The SDK ships its own login screen (native Apple on iOS, in-app browser
// OAuth for Google / GitHub / GitLab / Microsoft, plus email + password)
// and a machine picker that lists the user's own dev boxes plus guest-
// shared machines. Works LAN-direct and over Convex/relay off-LAN so
// Hermes bundle reloads keep working on cell data.
if (__DEV__) {
YaverFeedback.init({ trigger: 'shake' });
}
// In your root component:
<FeedbackModal /> // Embeds login + machine-picker modals automatically
Quick start (Flutter):
import 'package:yaver_feedback/yaver_feedback.dart';
void main() {
if (kDebugMode) {
YaverFeedback.init(FeedbackConfig(
trigger: FeedbackTrigger.floatingButton,
mode: FeedbackMode.narrated,
agentCommentaryLevel: 5,
));
}
runApp(MyApp());
}
// Add the floating button:
Stack(children: [child, const YaverFeedbackButton()])
What each SDK includes:
- Device discovery β auto-finds your Yaver agent on the LAN
- Connection UI β URL input, connect button, status indicator
- Screen recording β ReplayKit (iOS), MediaProjection (Android), getDisplayMedia (Web)
- Voice annotation β microphone recording synced to timeline
- Screenshot capture β tap to annotate at any moment
- P2P upload β multipart POST to agent, works through relay
- Three runtime modes β user selects live/semi/post at runtime
- Agent commentary β chat-like view of agent's observations
- Voice commands β "fix this now", "push to TestFlight", "run the tests"
- Auto-disabled in production β only active in
__DEV__/ development mode
CLI commands:
yaver feedback list # List bug reports from device testing
yaver feedback show <id> # View timeline, transcript, screenshots
yaver feedback fix <id> # AI agent creates a fix task from the report
yaver feedback delete <id> # Delete a report
Dogfooding: Yaver's own mobile app embeds its own feedback SDK. We develop Yaver with Yaver.
QA Testing Workflow
Combine push-to-device with the Feedback SDK for a complete QA loop:
1. Push to device: yaver push
2. Test on real phone: tap around, find bugs
3. Report bug: shake phone β screenshot + voice β sent to AI agent
4. AI fixes it: agent sees screenshot, reads stack trace, writes fix
5. Re-push: yaver push β fix on device in ~4s
6. Repeat
No TestFlight queues. No Play Store reviews. Real-device testing in seconds. Works with any AI agent (Claude Code, Codex, Aider, Ollama).
MCP Integration
Yaver implements the Model Context Protocol (MCP) with 473 tools. Its one-command setup path currently auto-registers with Claude Code, Codex, and opencode; other MCP clients can use the manual JSON config below.
One-Command Setup
yaver mcp setup claude-code # Claude Code user MCP config
yaver mcp setup codex # Codex CLI MCP config
yaver mcp setup opencode # opencode MCP config
yaver mcp setup show # Show config JSON (copy/paste manually)
The repo also ships registry metadata in server.json and glama.json so Yaver can be indexed by the official MCP Registry and Glama.
Manual Setup β Any MCP Client
Add to your claude_desktop_config.json:
{
"mcpServers": {
"yaver": {
"command": "yaver",
"args": ["mcp"]
}
}
}
For Claude Code, Yaver can register itself through the Claude CLI instead of editing files manually:
claude mcp add --scope user yaver -- /path/to/yaver mcp
yaver auth and yaver serve now try to do this automatically when claude is on PATH.
Network MCP (HTTP) β Remote / Claude Web UI
yaver mcp --mode http --port 18090
Connect from any MCP client at http://your-machine:18090/mcp.
GitHub Action
Trigger AI tasks from CI/CD:
- uses: kivanccakmak/yaver.io@main
with:
agent-url: ${{ secrets.YAVER_AGENT_URL }}
webhook-secret: ${{ secrets.YAVER_WEBHOOK_SECRET }}
prompt: "Review this PR and suggest improvements"
runner: claude
Available MCP Tools
| Category | Tools | Count |
|---|---|---|
| Docker | ps, logs, exec, build, push, pull, prune, stats, inspect, compose, networks, volumes | 23 |
| Kubernetes | pods, logs, describe, get, apply, exec, top, events, contexts, namespaces | 11 |
| Terraform | plan, apply, state, output, init, validate | 6 |
| Helm | list, status, values, search, repos, history | 6 |
| Git | info, stash, blame, reflog, branches, tags, log advanced, shortlog, stats | 13 |
| Compilers | gcc, clang, clang-tidy, clang-format, objdump, nm, binary size | 8 |
| Rust/Cargo | build, test, clippy, fmt, doc, bench, tree, update, audit, check, add/remove | 14 |
| Go | build, test (race/cover), vet, mod tidy/graph/why, generate, staticcheck, vulncheck | 11 |
| Python | pytest (coverage/markers), ruff (check/format/fix), mypy, black, pip-compile, uv | 6 |
| Node/TS | npm run, tsc, eslint (--fix), prettier, biome (check/format/lint) | 5 |
| Make/CMake | targets, run, clean, configure, build, test, install | 7 |
| Static Analysis | cppcheck, shellcheck, hadolint, semgrep, bandit, gosec, trivy | 10+ |
| Profiling | valgrind (memcheck/callgrind/massif), perf, strace, ltrace, go pprof | 10+ |
| Testing | run_tests (auto-detect), lint, format_code, type_check, benchmark | 4 |
| Dependencies | outdated, audit, list β npm/pip/cargo/go auto-detect | 3 |
| Package Registries | npm, PyPI, crates.io, Go modules, pub.dev, Homebrew, RubyGems, Maven, NuGet, Docker Hub | 24 |
| GitHub + GitLab | PRs, issues, CI, releases, stars, trending, MRs, pipelines | 10 |
| Platforms | Supabase, Convex, Cloudflare (Workers/Pages/R2/D1/KV), Netlify, Firebase, Fly.io, Railway | 33 |
| Database | query + schema (SQLite, Postgres, MySQL, Redis) | 2 |
| Network | tcpdump, tshark, nmap, netcat, port scan, arp, traceroute, mtr, curl timings | 18 |
| Linux Sysadmin | dmesg, lsmod, modprobe, systemctl, journalctl, ufw, iptables, df, du, lsblk, tree, top, ps, vmstat | 30 |
| Smart Home | Home Assistant, Philips Hue, Shelly, Sonos, Nanoleaf, Elgato, Tasmota, Govee | 20 |
| Mobile Dev | App Store, TestFlight, Play Store, Xcode, Gradle, Flutter, Expo, CocoaPods | 25 |
| Daily Utils | JWT decode, epoch, cron explain, subnet calc, fake data, domain check, color, QR | 13 |
| Finance | stocks, crypto, currency exchange | 3 |
| Location | EV charging, restaurants, hotels, geocode, directions, weather | 9 |
| Productivity | standup, changelog, gist, badges, gitignore, license, invite | 13 |
| Desktop | notify, volume, music, TTS, timer, calculator, clipboard | 26 |
| Core | tasks, sessions, tmux, scheduling, email, notifications, ACL, MCP peers | 67 |
See MCP Integration Guide for full documentation.
Headless Clients (script the phone + dashboard from Node)
Two npm packages that expose the exact same HTTP / Convex / relay surfaces Yaver's mobile app and web dashboard use β but without any native runtime. Drive them from bun / node scripts, CLI pipelines, or MCP tool calls. Good fit for CI smoke tests, AI-assisted QA bots, remote control from SSH-only boxes, and anything where "open the UI and click the button" isn't an option.
| Package | What it drives | When to use |
|---|---|---|
yaver-mobile-headless | The React Native mobile app's lib (beacon discovery, Apple/OAuth auth, phone-project scaffolder, Hermes bundle push, shake-to-reload gesture) | You're automating anything that would otherwise require the iPhone / Android app to be open β LAN beacon discovery, push-to-device flows, phone-project CRUD, QA runs that simulate a tester shaking the phone. |
yaver-web-headless | The web dashboard's agent-client (dev-server preview URL composition, webview reload, vibing task dispatch, Reconnect & Fix recovery, /settings/repair-relay) | You're automating the browser dashboard β starting / stopping Vite + Next + Expo + Flutter dev servers, tailing preview URLs, kicking coding tasks, or running the full recovery loop when the iframe 401s. |
Common shape: connect(deviceId) β agent methods β JSON on stdout. Same ENV vars (YAVER_TOKEN, YAVER_CONVEX_URL). Mix them in the same script when a flow needs both (e.g. sign in once, tail dev-server logs via web-headless, then fire a shake gesture via mobile-headless).
# Install either or both globally
npm install -g yaver-mobile-headless yaver-web-headless
# Mobile: scaffold + push a phone project
yaver-mobile-headless phone-project-create --name="Todo" --template=todos
yaver-mobile-headless phone-project-push --slug=todo --base-url=https://your-box.example.com --target-token=$CLOUD_TOKEN
# Web: start a Vite dev server on a remote box and print the iframe URL
export YAVER_TOKEN=$(yaver-web-headless sign-in --email=... --password=... | jq -r .token)
yaver-web-headless dev-start --device=$DEVICE_ID --framework=vite --work-dir=/workspace/myapp
yaver-web-headless webview-url --device=$DEVICE_ID
Full reference and package-specific verbs: docs/headless-clients.md.
Web Search MCP Tool
Yaver ships a built-in web_search MCP tool so any connected AI agent (Claude Code, Codex, Aider, ...) can ground its output in current information β competitor research, library docs, error messages, news β without each agent needing its own search integration.
| Provider | Cost | Setup |
|---|---|---|
| DuckDuckGo (default) | Free, no key | Works out of the box |
| Paid (free tier 100 q/day) | export GOOGLE_CSE_KEY=β¦ GOOGLE_CSE_CX=β¦ (Programmable Search Engine) | |
| Bing | Paid | export BING_API_KEY=β¦ (Azure Bing Search v7) |
Set provider: "auto" and Yaver picks the best available backend (Google β Bing β DuckDuckGo). Used directly by yaver handoff autodev for market-gap research during proactive-mode handoffs.
Pass Session to Yaver (Handoff)
Hand off an in-progress AI session β Claude Code, Codex, Aider, anything β to Yaver, and let Yaver's autodev loop finish the remaining work autonomously. Works on the current machine, on a remote dev box, with hybrid (planner + cheap local implementer), or with a single arbitrary runner.
# Default: claude-code finishes the work locally
yaver handoff
# Cheap: planner + token-leaner implementer (Claude plans, opencode implements)
yaver handoff --engine hybrid
# Specific runner
yaver handoff --engine runner --runner codex
yaver handoff --engine runner --runner opencode
# Hand a specific Yaver task or session file
yaver handoff --from <taskId>
yaver handoff --from ~/.claude/sessions/<uuid>.jsonl
# Hand off to a remote dev machine
yaver handoff --to my-mac-mini --engine hybrid
# Add focus, set caps
yaver handoff --message "finish the failing tests first" --max-kicks 50 --deadline 3600
From inside an AI agent. Any agent connected to Yaver's MCP server can call the session_handoff tool β say "pass session to yaver" and the agent invokes it. The tool returns exitNow: true plus a sentinel file path, signalling the agent to terminate cleanly. Yaver writes ~/.yaver/handoff/<loopName>.json (and a stable latest.json) so external agents that can't be force-killed can poll for the takeover and exit on their own.
What Yaver does on handoff:
- Exports the source session to a
TransferBundle(conversation turns + agent-specific state files). - Imports it into the target machine's TaskManager.
- Optionally stops the source Yaver task.
- Builds a develop-mode autodev loop with the chosen engine/runner. The resume prompt is synthesised from the bundle context plus pending items in the todo list plus any
--message. - Writes the sentinel and kicks the loop immediately.
Engine choices:
| Engine | Runner | When to use |
|---|---|---|
claude (default) | claude-code | Highest quality, frontier model end-to-end |
hybrid | planner=claude, implementer=opencode | Cheaper on long feature loops; opencode routes to whichever provider you've BYOK'd |
runner | one of claude-code / codex / opencode | You know exactly which runner you want |
Surfaces: CLI (yaver handoff), MCP tool (session_handoff), HTTP (POST /session/handoff). Same arguments across all three.
Hard takeover (vs cooperative). Yaver doesn't just write a sentinel β it actually terminates the calling AI process. Caller PID is resolved in this order: explicit --caller-pid / caller_pid arg β stdio MCP parent PID (auto-set when Claude Code/Desktop spawns yaver mcp) β HTTP MCP loopback peer port via lsof. After the response is sent, Yaver sends SIGTERM and SIGKILLs 5s later if the process is still alive. Non-loopback HTTP clients are never killed.
Load + duration knobs (mirror yaver autodev). --load lite (default) stretches kicks to one every 5min and respects the dev's Claude/Codex 5-hour windows. --load burst runs every 30s up to 200 iterations/day. --hours 8 caps each individual kick at 8h so a runaway prompt can't burn the whole budget.
Verify takeover: yaver handoff status prints the most recent sentinel + the live loop's iteration count and last summary.
Full autodev parity. Everything yaver autodev exposes is also a handoff flag, so a session takeover can be configured exactly like a from-scratch autodev run:
| Flag | Effect |
|---|---|
--prompt "..." | Explicit focus prompt (replaces the auto-resume prompt) |
--target web|ios-sim|android-emu | Loop target (default: auto-detect from workdir) |
--branch <name> / --auto-branch | Ship to named branch / autodev/<loop>-<YYYYMMDD> |
--deploy | Default = ship to all configured platforms. Disable with --deploy false/no/0/none. Restrict to one platform with testflight/playstore/web. |
--notify | Mobile notification when the loop ends |
--no-autotest | Skip interleaved regression test pass |
--auto-ideas N | Cap on idea-refill batches when checklist runs dry |
--remained <path> | Pull next item from a remained.md checklist |
--lite / --heavy | Shortcuts for --load lite/burst |
--engine hybrid / --hybrid | Cheap planner+local-implementer mode |
Security Sandbox
The command sandbox is enabled by default and blocks dangerous operations:
- Filesystem destruction:
rm -rf /,rm -rf ~, etc. - Encryption/ransomware: bulk encryption of home/root
- Privilege escalation:
sudo,su,doas(unless allowed) - Disk manipulation:
mkfs,fdisk,ddto block devices - Network exfiltration:
curl|bash, piping sensitive files - System compromise: overwriting
/etc/passwd, disabling services
Configuration
// ~/.yaver/config.json
{
"sandbox": {
"enabled": true,
"allow_sudo": false,
"blocked_commands": ["terraform destroy", "kubectl delete namespace"],
"allowed_paths": ["/home/user/projects"],
"max_output_size_mb": 100
}
}
yaver config set sandbox.allow-sudo true # Allow sudo
yaver config set sandbox.enabled false # Disable sandbox (not recommended)
Multi-User Support
Multiple users can share the same machine (e.g. shared GPU server with Ollama). Each user runs their own agent:
# User A
yaver auth && yaver serve --port 18080
# User B
yaver auth && yaver serve --port 18081
Each agent instance has:
- Separate auth token and user ID
- Isolated task store (
~/.yaver/tasks.json) - Own sandbox configuration
- Independent relay connections
- Auth-aware LAN beacon (only same-user devices discover each other)
Cloudflare Tunnel
For a single always-on box, Cloudflare Tunnel is the easiest non-relay path from phone to machine. Yaver still does auth and permission checks; Cloudflare is only the HTTPS transport.
# Start the agent on the box
yaver auth
yaver serve
# Guided permanent setup
yaver tunnel cloudflare wizard
The wizard shells out to cloudflared, logs you into Cloudflare, creates a named tunnel, writes ingress to http://127.0.0.1:18080, creates the DNS route, and stores the resulting https://... URL in Yaver config.
For a quick temporary test:
cloudflared tunnel --url http://localhost:18080
yaver tunnel add https://<random>.trycloudflare.com
How Yaver uses it:
- Same-owner phone + box: mobile tries LAN first, then Cloudflare Tunnel, then relay.
- Requests still carry
Authorization: Bearer <your-yaver-token>. - If you added Cloudflare Access service-token headers, Yaver can attach them locally on the host/client side too.
Important limitation: the account-level tunnelUrl sync is best for the simple case: one user, one primary box, one stable tunnel URL. If you have multiple boxes behind the same Yaver account, prefer per-device custom tunnels, direct LAN/Tailscale, or relays unless you are sure the tunnel URL belongs to the exact box you want.
Guest Access
Share your machine with anyone β no team or subscription needed. Invite by email, they accept from the Yaver app. Guests can run tasks and use dev server but cannot access shell, vault, or sessions.
# Invite a guest
yaver guests invite cousin@gmail.com
# β Invite code: K7WP3N (share this if they sign up with a different email)
# Configure guest limits
yaver guests config cousin@gmail.com limit=3600 mode=scheduled
yaver guests config cousin@gmail.com runners=claude,opencode
yaver guests config cousin@gmail.com machines=mac-mini,laptop
yaver guests config cousin@gmail.com guestkeys=false tunnels=false
yaver guests config cousin@gmail.com isolation=true
# View guest usage
yaver guests usage
# List all guests
yaver guests list
# Revoke access
yaver guests remove cousin@gmail.com
Guest config options:
| Setting | Values | Default | Description |
|---|---|---|---|
limit | seconds/day | unlimited | Daily task-seconds cap (e.g. 3600 = 1 hour/day) |
mode | always, idle-only, scheduled | always | When the guest can use the machine |
runners | comma-separated | all | Which AI runners the guest can use |
machines | comma-separated device IDs | all shared by grant | Restrict access to some host machines instead of all |
guestkeys | true, false | true | Allow guest-supplied API keys on shared infra |
tunnels | true, false | false | Allow raw tunnel forwarding to host-local services |
isolation | true, false | false | Force Docker isolation for guest-triggered tasks |
How it works:
- Host invites via CLI, mobile app, or MCP (
guest_invitetool) - Guest signs in to Yaver app with any OAuth (Apple, Google, Microsoft)
- Guest accepts via email match or 6-character invite code
- Host's devices appear in guest's device list
- Max 5 guests per host, invitations expire in 2 days
Config (limits, runners, usage mode) syncs via Convex. Project access is managed P2P on each agent.
Sharing Infra Safely
There are three different sharing shapes:
- Share a box / some boxes: invite a guest and scope them to one machine or a selected set of machines.
- Share infra but not raw secrets: let the guest use host-managed runners / build tools / storage under Yaver policy, while keeping raw provider values private.
- Share code scope, not your whole disk: narrow the guest to selected projects so tasks, feedback fixes, and file browsing stay inside approved repos.
Examples:
# One teammate can use only the Mac mini and only the yaver repo
yaver guests invite teammate@example.com --scope=full --machines=mac-mini --projects=yaver
# End-user / tester: feedback-only access to one app project
yaver guests invite tester@example.com --projects=sfmg
# Existing guest: remove host-managed key usage, disable raw tunnels, require containers
yaver guests config teammate@example.com guestkeys=false tunnels=false isolation=true
Guest + Host Cloudflare Tunnel
If the host has already set up Cloudflare Tunnel for a box, a guest can benefit from that faster HTTPS path without having any Cloudflare account at all.
- Guest signs into Yaver only.
- Guest presents their own Yaver bearer token to the host agent through the host's tunnel URL.
- Host agent validates that token, checks guest scope / machine / project policy, and only then serves the request.
- Cloudflare carries bytes; Yaver decides authorization.
What the guest does not need:
- a Cloudflare account
cloudflared- their own domain
- direct access to Cloudflare credentials
What stays host-only:
- Cloudflare Access service-token secrets (
CF-Access-Client-Id/CF-Access-Client-Secret) - the raw tunnel setup itself
- machine-level policy decisions
Caveat: automatic host-tunnel reuse is intentionally conservative. Yaver only projects an account-level tunnel hint onto a shared device when the share resolves to exactly one host box. If a host shares multiple devices under one account-level tunnel setting, guests should use relay/direct paths or host-specific tunnel entries instead of guessing.
Repo / Workspace Sharing
Classic guests is the safe βuse parts of my machineβ model. For deeper repo-oriented collaboration, Yaver also has a host-share surface for brokered workspace sessions:
yaver host-share prepare
yaver host-share create --projects yaver --session-ttl-min 480 --idle-timeout-min 30
yaver host-share join <invite-code>
yaver host-share attach-repo --session <session-id> --path ~/code/yaver
yaver host-share sync-repo --session <session-id> --to-host
yaver host-share sync-repo --session <session-id> --from-host
yaver host-share end <session-id>
For the "my friend keeps the repo on their own machine, but borrows my Codex/tools" flow, the guest now attaches a local repo root to the borrowed workspace explicitly:
attach-repobinds one discovered local repo root to the session and seeds the host-side borrowed workspace from that guest machine.sync-repo --to-hostrefreshes the borrowed workspace from the guest repo.sync-repo --from-hostwrites host-side workspace changes back to the guest repo.- If
attach-repocannot find the repo, runyaver repo refreshon the guest machine first so the root is discoverable.
That keeps the repo authority on the guest machine while the heavy runner/tool execution stays on the host.
Host control is explicit:
--session-ttl-minsets the hard lease lifetime when the invite is created.--idle-timeout-minends the lease if the session goes inactive.yaver host-share end <session-id>stops an active session immediately.yaver host-share revoke <invite-code>revokes the invite and any session created from it.
Use guests when you want:
- tasks
- feedback
- dev server
- bounded file/project access
Use host-share when you want:
- a session-style collaboration flow
- brokered workspace operations
- guest-owned repo mirroring into a host-backed workspace
- tighter repo-level boundaries for a specific sharing session
Neither model gives the guest your shell, vault, or raw provider secrets by default.
Vault & Deploy Script Generator
Yaver has an on-device vault that behaves like GitHub/GitLab secrets but stays on your own machines. Secrets are grouped by project, encrypted at rest (NaCl secretbox + Argon2id), and sync peer-to-peer between your paired devices β never through our servers.
A deploy-script generator sits on top of it: given an (app, target)
pair it emits a bash script that reads from the vault, runs a
toolchain preflight, and executes the build + upload commands on
your own machine. "Your machine = your CI runner" without the cloud
CI bill.
# 1. Put credentials in the vault (project-scoped).
yaver vault add APP_STORE_KEY_PATH --project mobile --value ~/keys/AuthKey.p8
yaver vault add APP_STORE_KEY_ID --project mobile --value <your-key-id>
yaver vault add APP_STORE_KEY_ISSUER --project mobile --value <your-issuer-uuid>
yaver vault add APPLE_TEAM_ID --project mobile --value <your-team-id>
# 2. Check the toolchain + vault are ready to ship.
yaver doctor build --target testflight --project mobile
# 3. Generate a reviewable bash script.
yaver deploy generate --app mobile --target testflight --out scripts/deploy-mobile-ios.sh
# 4. Ship. The script sources the vault, runs the preflight gate,
# then xcodebuild β export β upload to App Store Connect.
bash scripts/deploy-mobile-ios.sh
# 5. Sync the vault to your other Yaver-paired devices.
yaver vault sync
Supported targets out of the box: testflight, playstore,
cloudflare, convex, npm-publish, pypi-publish. Adding one
is ~10 lines in desktop/agent/deploy_script_gen.go.
The existing scripts/deploy-*.sh are vault-aware too β drop values
in the vault once and they stop needing export in every shell.
GitHub Actions keep working unchanged: a CI host with no vault just
falls through to env vars set by secrets.*.
Shared-machine deploys (yaver deploy ship)
Guests you invite with the new deploy scope can trigger a deploy
on your machine from their laptop, without ever seeing the
secrets on your disk:
# Host
yaver guests invite friend@example.com --scope=deploy --projects=mobile
# Guest β runs on their laptop; the build actually happens on yours
yaver deploy ship --app mobile --target testflight --machine <host-device-id>
The script body is generated on your machine, vault values are
injected into the subprocess env (never into the script source),
and only stdout/stderr stream back over SSE. Security model in
docs/vault-and-deploy.md.
Ship to multiple stores at once:
yaver deploy ship --app mobile --targets testflight,playstore
One request, server-side fan-out. Preflight runs for every target
upfront β the whole composite is rejected atomically if anything is
missing. Events from per-target goroutines multiplex into a single
SSE stream with a target field; the CLI demuxes them with
[testflight] / [playstore] prefixes, prints a ββ composite summary ββ at the end, and exits with the worst per-target code.
Past runs are queryable:
yaver deploy runs # table of recent runs
yaver deploy logs <run-id> # full on-disk log of a past run
yaver deploy diagnose --app mobile --target testflight # preflight
In-memory ring buffer, last 100 runs. Each run stores who
triggered it, what target, exit code, duration, and the last ~8 KB
of stdout/stderr. The full output is also written to
~/.yaver/deploys/<id>/output.log so yaver deploy logs <id> can
replay the full build, not just the tail. Guests only see their own
runs.
Failures are auto-classified: vault_locked, toolchain_missing,
auth_error, signing_error, network_error, timeout,
already_uploaded (which is Apple's way of saying "this build is
already shipped" β treated as success, not failure), plus generic
build_failed when nothing specific matches.
If Apple upload hiccups after a 20-min archive, just rerun β the
iOS template is idempotent. The archive lives at
/tmp/yaver-deploy-<app>-testflight.xcarchive; the second run
checks its CFBundleVersion + mtime and skips straight to the
30-second export+upload phase. On success the archive is cleaned
up; on failure it's kept for the next attempt.
Want a ping on completion? Set deploy_webhook_url in
~/.yaver/config.json to a Slack/Discord/Zapier inbound URL. Every
finished run POSTs {id, app, target, exit_code, duration_ms, ok, error_class, is_guest, ...} β fire-and-forget, one retry on
non-2xx, then logged-and-forgotten. Especially useful for
overnight guest-triggered deploys where nobody is watching the
terminal. Add deploy_webhook_secret to get HMAC-signed POSTs
(X-Yaver-Timestamp + X-Yaver-Signature: sha256=<hex> over
"{timestamp}.{body}" β same shape as Slack / GitHub / Stripe).
Full reference: docs/vault-and-deploy.md.
Container Sandbox (Optional)
Run AI agent tasks inside Docker containers for full filesystem isolation. Optional and disabled by default β the default mode runs tasks directly on the host.
# Build the sandbox image (one-time, ~3 min)
yaver sandbox build
# Enable for guests only (security isolation)
yaver serve --containerize-guests
# Enable for all tasks (clean build environments)
yaver serve --containerize-host
# Check status
yaver sandbox status
What's in the container: Node.js, Python, Go, Rust, Java, Ruby, Claude Code, Aider, Expo CLI, Wrangler, and common build tools. Build caches (npm, Gradle, Cargo, Go modules) persist across tasks via Docker volumes.
Project-specific containers: Place a Dockerfile.yaver in your project root for custom toolchains. The agent auto-detects and builds it.
Extra host mounts (e.g. Android SDK): add to ~/.yaver/config.json:
{
"container_mounts": ["/opt/android-sdk:/opt/android-sdk:ro"]
}
Note: Xcode/xcodebuild requires macOS and cannot run in Docker. iOS builds must use direct execution (non-containerized). Android builds via Gradle work fully inside containers.
Hot Reload β Dev Server to Phone
Start a dev server on your machine and preview the app on your phone in real time β all through the P2P channel. Works on any network (Wi-Fi, 4G, behind NAT).
# From the Yaver mobile app: tap a project β Open App
# Or from CLI:
yaver dev start --framework expo # Expo / React Native
yaver dev start --framework flutter # Flutter
yaver dev start --framework vite # Vite
yaver dev start --framework nextjs # Next.js
Linux / WSL / Remote iPhone Workflow
For React Native / Expo, this is a first-class path:
- Run
yaveron Linux, WSL, or a remote box - Pair your iPhone with the Yaver mobile app
- Start Metro on the host
- Tap
Open in Yaveron the phone - Yaver builds a Hermes bundle on the host and pushes it into the Yaver iPhone app
This means your daily iPhone dev loop does not need Xcode or a Mac. The iPhone behaves like a real device attached to your remote workflow, not like a simulator tied to a local Mac.
What still needs macOS:
- building a standalone native iOS binary
- code signing / provisioning
- App Store / TestFlight shipping
What does not need macOS:
- React Native / Expo JS iteration
- Metro-based hot reload on a real iPhone through Yaver
- relay / Tailscale / remote-box workflows
If you are on Linux or WSL, Yaver should use the Hermes bundle path for iPhone work rather than xcodebuild.
Hermes reload β when it crashes and how to fix it
TL;DR β this can fail with apps that use native modules Yaver doesn't know about. The bundle download is rock-solid; the structural limit is what's compiled into Yaver's iOS / Android super-host. Apple forbids loading new native code at runtime, so the set of native modules a guest bundle can call equals the set already baked into the signed Yaver binary on disk (currently 113 modules in
mobile/sdk-manifest.json). Anything outside that set will surface in the "Incompatible native modules" dialog before the bridge swap; if you tap "Load anyway" and the JS actually calls the missing module, Hermes will crash. Background + mitigation roadmap:HERMES_RELOAD_STATUS.md,docs/native-module-architecture.md,docs/android-dynamic-native-modules.md, and the blog post Hermes vs WebView.
The bundle download path is reliable end-to-end (streaming relay protocol verified for 8.5 MB+ Hermes bytecode). But the bundle is just JS bytecode β it executes inside Yaver's iOS super-host and can only call native modules the host registers. If your app declares a native module that Yaver doesn't know about, the build still succeeds and the bundle still loads, but the JS will eventually call a TurboModule selector that resolves to nil, throw an NSException, and crash Hermes during the JSError-construction path.
The handshake check (cli/v1.99.94+)
Before every "Open in Yaver", the agent now diffs the project's package.json dependencies against Yaver's embedded mobile/sdk-manifest.json. The mobile app receives the missing-module list in the build response and shows you an "Incompatible native modules" dialog before doing the bridge swap. You can cancel, or Load anyway if you know the missing modules are guarded behind feature flags or platform checks.
The check is non-blocking on the agent side β the bundle still gets served β because there are legitimate cases (the Yaver Feedback SDK is one) where a "missing" module self-suppresses inside Yaver. The mobile dialog is the safety gate.
Common crash classes
| Symptom | Probable cause | Where to look |
|---|---|---|
EXC_BAD_ACCESS in hermes::vm::HiddenClass::isDictionary() after convertNSExceptionToJSError | A TurboModule selector threw NSException, Hermes crashed converting it to a JS error. Almost always: the module isn't in Yaver's super-host. | Compare your package.json deps vs mobile/sdk-manifest.json::nativeModules. |
Native module 'X' is null thrown immediately after bundle load | TurboModuleRegistry.getEnforcing('X') ran during a static initializer and X isn't registered. | Same diff. Either add the module to Yaver, or guard the call with if (NativeModules.X). |
BC_VERSION_MISMATCH rejection | Project compiled against a different Hermes than Yaver ships. | Make sure hermesc from your RN install isn't being substituted; Yaver-cli embeds the canonical hermesc for BC 96. |
| Bundle downloads then silently does nothing | App is bundleless β the user's bundle is plain JS, not Hermes bytecode (HBC magic at offset 4 should be 0x1F1903C1). | Inspect with xxd /tmp/<bundle>.jsbundle | head -1. If magic is missing the build pipeline never ran hermesc. |
| Fine on macOS host, crashes from Linux/WSL host | The compatibility check is the same on both β but a stale macOS DerivedData cache can mask a real native dep mismatch by reusing pre-built native code. Linux can't do that. | Always trust the Linux/WSL run when the two diverge. |
Adding a native module β invitation to PR
If your project depends on a native module that's missing from Yaver's super-host, the right fix is to add it. The contract:
- Add the npm package to
mobile/package.json. - Add a matching entry to
mobile/sdk-manifest.jsonundernativeModules(key = npm package name, value = installed version). - Mirror the manifest into
mobile/android/app/src/main/assets/sdk-manifest.json,mobile/ios/Yaver/sdk-manifest.json,cli/sdk-manifest.json, anddesktop/agent/sdk-manifest.json. TheTestSDKManifestInSyncGo test fails the build if the agent copy drifts from the mobile master. - For the iOS path:
cd mobile/ios && pod install, then make sure the module's headers and bridging code are reachable frommobile/ios/Yaver.xcworkspace. Most autolinked modules need no manual wiring beyondpod install. - For Android:
cd mobile/android && ./gradlew clean, then re-bundle. Autolinking handles the registration. - Open a PR. Include:
- The
sdk-manifest.jsondiff - One smoke-test scenario (e.g. "loaded SFMG which uses
react-native-record-screenβRecordScreen.startRecording()no longer throws"). - The Hermes BC version you tested against (currently 96).
- The
The sdk-manifest.json is the source of truth for "what Yaver guarantees a guest bundle can call". Adding a module here is a public commitment that the iOS and Android super-hosts both register it. Don't add a module to the manifest before the corresponding native code is wired β it'll just push the crash from the build-time warning to a runtime SIGSEGV. The TestSDKManifestInSync test catches drift between the agent and the mobile master, but it can't catch "manifest claims X is registered but no RCT_EXPORT_MODULE exists." That's a manual review item.
For follow-up reading:
HERMES_RELOAD_STATUS.mdβ current state of the agent β relay β phone handshake, what's verified, what's still stubbed.docs/native-module-architecture.mdβ full developer reference: the five mirrored manifest copies, the heuristic, the PR contract, common failure modes.docs/android-dynamic-native-modules.mdβ design sketch for an Android-only fast path that side-steps the wall by leveragingdlopen. Not shipped yet.- Blog post: Hermes Bytecode vs WebView β what Hermes is, how iOS and Android allow runtime injection, where WebView fits, and where the long-tail-of-modules problem comes from.
Roadmap for closing the gap
The handshake catches mismatches today. Three more layers planned:
- Auto-stub at build time. When the agent finds an incompatible module, inject a JS-side proxy that returns a controlled rejection (
Module X is not available inside Yaver) instead of throwing NSException. Apps that gate optional features behindif (Module.isAvailable)keep working β the specific feature is just disabled. Stops crashes for ~80% of cases. - Popular-module preload. Bake the top 30-50 most-commonly-needed RN native modules into Yaver's super-host as one-time integration work. Binary grows ~30-50%, but the wall recedes for most users.
- Per-project Yaver build. For high-value cases, build a custom Yaver-X binary in CI with that project's native modules linked in, ship via that user's Apple Developer account or ad-hoc enterprise distribution. Same model EAS Build uses for production apps.
- Android dynamic loading. Android allows
dlopenof arbitrary.sofiles at runtime. The agent could cross-compile a missing module on the host, stream the.soto the phone via the relay, andSystem.loadit before the bridge swap. Only works on Android (Apple forbids it on iOS) β but it's a real escape hatch for Android-first teams. Seedocs/android-dynamic-native-modules.md.
Mobile-First Backend Continuum
Yaver is not just a phone-to-screen bridge. For the phone-project flow, the phone can be the first backend tier.
The same portable project bundle can move across three targets:
| Tier | What runs it | Typical use |
|---|---|---|
| Phone sandbox | Yaver mobile app | first CRUD loop, offline prototyping, quick demos |
| Your dev machine / your own host | yaver serve on Mac, Linux, WSL-adjacent box, Pi, VPS, or remote machine | real-device testing, staging, privacy-sensitive self-hosting, or a remote coding box that runs your web UI + backend with Claude Code / Codex / similar agents |
| Yaver Cloud | the same yaver serve behind the cloud/ stack | managed deployment with zero-ops setup |
For a current-state audit of the mobile-first dedicated VPS flow, plus a practical setup path that approximates the future Yaver Cloud experience today, see docs/yaver-cloud-mobile-runbook-audit.md.
The promotion unit is the same portable manifest every time:
- schema
- auth personas
- seed data
- optional live SQLite rows
- generated SQL
- app spec and related metadata
This is the intended full-stack vibe-coding loop:
- Create the project from the phone.
- Prompt or edit the app and backend from the phone.
- Run it locally in the phone sandbox.
- Promote it to your own machine or cloud when it needs to grow.
- Export or migrate only if you want an escape hatch later.
One important promoted shape is the remote dev box: the app lives on a Linux/macOS/VPS machine, that machine runs the web UI and backend plus coding agents like Claude Code or Codex, and Yaver uses the phone as the control/view surface. In that flow the phone does not just trigger prompts. It can tell the box to run the app, run tests, and surface a live terminal, recording, or VNC-like stream so the user can watch what the remote box is doing from mobile.
Project-Owned Remote Command Contract
For monorepos and self-hosted app stacks, the clean pattern is to let the repo expose one stable argv contract that Yaver can call on the selected machine.
Example:
./scripts/yaver_project_entry.sh \
--project my-app \
--machine primary \
--build web
or:
./scripts/yaver_project_entry.sh \
--project my-app \
--machine primary \
--build test-selenium
The important part is not the filename. The important part is the shape:
--project <project>--machine <alias>--build <target>
primary is the safe public example because Yaver already resolves it to the user's selected machine. Public docs should prefer aliases like primary or selected-machine over real hostnames, IPs, or internal device labels.
Typical --build values a repo might support:
bootstrapwebstop-webtest-yavertest-seleniumdeploy-webdeploy-backenddeploy-all
When --build web starts a preview, the repo-owned command should print a user-openable URL such as:
APP_URL=http://127.0.0.1:4173
and ideally persist the same result to a small JSON status file so mobile, web UI, HTTP, or MCP can read it back without scraping logs.
That URL is what the human opens. If the project has Yaver's web feedback SDK wired to the selected agent, the opened page can immediately participate in screenshot/fix/reload loops from the phone.
Containerized Backend Export
If you want the phone-created backend to land on your own server with Docker, use the phone export / push containerization path:
yaver phone export --containerize --include-data my-todos
yaver phone push --to https://your-box.example.com --containerize my-todos
The exported bundle can include:
Dockerfiledocker-compose.yml.env.example.dockerignore
That gives you a short path from phone sandbox to your own VM, Hetzner box, or other Docker-capable host without changing runtimes.
Monorepo Position
The product direction is phone-first full-stack development with a monorepo:
- mobile app
- backend
- shared schema/types
- deploy/export path from the same project root
That monorepo bootstrap story is a priority, but the one-tap repo scaffolder is still in progress. Today the core backend continuum and promote/export path exist first; monorepo automation sits on top of that.
WSL To iPhone Quickstart
If your code lives in WSL and you want real iPhone reload, the daily loop is:
- Install Yaver mobile on the phone.
- Run
yaver serveinside WSL. - Pair the phone with that agent.
- Open the Expo / React Native project from Yaver.
- Tap
Open in Yaver. - Let Yaver build Metro + Hermes on the WSL host and load the bundle inside the phone app.
Important boundary:
- WSL is supported for development and phone testing
- WSL is not the primary always-on deployment target for Yaver itself
- if you want the machine to survive power loss and come back without touching a terminal, prefer native Linux or macOS
- if you stay on WSL, use Yaver's WSL startup helper and Windows Scheduled Task path
- also disable Windows sleep; WSL itself cannot keep the Windows host awake
The important rule is:
- WSL iPhone reload = Hermes bundle into Yaver mobile
- WSL iPhone reload !=
xcodebuild - WSL reboot persistence uses a helper path, not native Linux systemd
- WSL unattended remote use depends on Windows power settings
Command-first version:
npm install -g yaver-cli
yaver auth
yaver serve
Optional: force iPhone work to stay on bundle mode explicitly:
yaver mcp call set_ios_install_method '{"method":"bundle"}'
Then from the phone:
- select the paired machine
- select the project
- tap
Open in Yaver
What should happen:
- Metro runs on the WSL host
- Hermes bundle builds on the WSL host
- the bundle is pushed to the phone
- the app runs inside Yaver on the iPhone
If your cousin only remembers one line, make it this:
WSL -> Hermes bundle -> Yaver mobile app
This is the intended path for projects like sfmg when they are Expo / React Native apps.
Contributor workflow:
- contributor clones
sfmgand edits source with Claude Code - contributor runs
yaver serve - contributor opens the project from the Yaver phone app
- if the project is source-only, Yaver now shows
Compile Hermes - contributor taps
Open in Yaverto test on the phone inside the Yaver container - contributor commits and pushes
- maintainer deploys the real TestFlight build later from the Mac/Xcode path
That means "never built before" is not a blocker for the daily contributor loop. Yaver can detect:
- source-only project that still needs its first Hermes compile
- previously compiled project that is ready to open
- last Hermes build failed and should be rebuilt after fixing the error
Troubleshooting shortcut:
- if the system tries to do a native iOS install on WSL, the mode is wrong
- on WSL the resolved iOS install method should be
bundle - missing native-module support is a container compatibility issue, not a WSL issue
Full guide: docs/wsl-ios-hermes-quickstart.md
Do I Need To Modify My Project?
Usually, no.
For the normal Yaver agent flow (yaver running on Linux, WSL, macOS, or a remote host):
- You do not need to inject the npm bootstrap package into the app
- You do not need to add the Feedback SDK just to open the app in Yaver
- Yaver starts Metro, builds the Hermes bundle, and loads it into the Yaver phone app
Use the npm package when:
- you want direct push-to-device workflows without the full agent
- you want compatibility analysis against Yaver's native module manifest
- you want watch-mode push from a terminal with
yaver push --watch
Use the Feedback SDK when:
- you want shake-to-report bug capture inside your own app
- you want remote reload commands sent into your own app process
- you want black-box event streaming and AI fix context
In short:
yaveragent + mobile app = enough for Hermes reload into Yaver on iPhone/Androidyaver-cli= npm distribution name for the unified bootstrap package- Feedback SDK = optional in-app debug/reload/reporting workflow
- the phone UI now exposes
Compile Hermes,Rebuild Hermes, andOpen in Yaveras separate steps for source-only third-party apps
What can still block success:
- unsupported native modules not present in the Yaver host container
- React Native / Hermes version mismatch for direct push workflows
- apps that depend on a custom native module outside Yaver's shipped manifest
Open App β dynamic dispatch (iOS)
The Yaver mobile app's Open App button dispatches dynamically based on the connection mode β never a WebView. Third-party React Native apps always load natively:
| Connection | What runs | Outcome |
|---|---|---|
| iOS + same Wi-Fi on macOS (direct LAN) | xcodebuild build (auto-detected .xcworkspace / .xcodeproj + scheme) inside ./ios/ with -allowProvisioningUpdates, then xcrun devicectl device install app + xcrun devicectl device process launch | App is installed + launched on the real device the same way Xcode would do it manually β fastest full-native path when Xcode is available. |
| iOS + cellular / relay | /dev/build-native runs the framework's bundler (expo export:embed or react-native bundle), compiles with embedded hermesc (BC96 from RN 0.81.5), ships the validated HBC over the P2P channel, phone loads it into the Yaver super-host via YaverBundleLoader (New Arch guest bridge with TurboModules + Fabric) | App runs inside Yaver with its full JS. Works over 4G / relay / anything. |
| iOS + Linux / WSL / remote host | Same Hermes HBC push path as relay mode | The normal non-macOS workflow. Develop anywhere, hot reload on a real iPhone, no Xcode in the daily loop. |
| Android | Hermes HBC push into the Yaver super-host (same path as iOS relay) | Single path β Android doesn't need a separate native install branch. |
The dispatch lives in mobile/app/(tabs)/apps.tsx's handleOpen + handleTapProject; the LAN native build uses the PlatformXcodeDeviceInstall build platform in desktop/agent/builds.go; and desktop/agent/device_install.go reads CFBundleIdentifier via PlistBuddy so the app auto-launches after install.
Supported frameworks:
| Framework | Dev Server | Hot Reload |
|---|---|---|
| Expo / React Native | Metro (npx expo start) | Auto (Metro watches files) |
| Flutter | flutter run -d web | Auto (r keystroke) |
| Vite | npx vite | Auto (Vite HMR) |
| Next.js | npx next dev | Auto (Fast Refresh) |
Expo modes: LAN native install on macOS (same Wi-Fi + iOS), Hermes HBC push to the Yaver super-host (any network, including Linux/WSL/remote hosts), or raw dev client (custom native build with all native modules).
Remote Reload β Trigger from Your Phone
When a third-party app has the Feedback SDK embedded and is connected to the same agent, you can trigger a reload from the Yaver mobile app β even while away from your desk. The agent broadcasts the reload command to all connected SDK devices via a persistent SSE command channel.
Yaver Mobile App ββtap "Reload"βββΊ Agent ββSSE pushβββΊ Third-Party App (Feedback SDK)
β ββ onReload() callback
ββ /dev/reload-app ββ auto DevSettings.reload()
Two modes: dev (hot reload from dev server) and bundle (rebuild Hermes bytecode + push). Works over both direct LAN and relay connections.
For the full current-state model of auth, re-auth, discovery, reload, vibing, feedback SDK control, and phone sandbox export/promotion, see docs/runtime-control-plane.md.
Push to Device β Test Existing RN Apps on Real Hardware
Yaver doubles as a native container app (like Expo Go, but for existing projects). Install the yaver.io app from the App Store / Play Store, then push your existing React Native project to it β no project modifications required.
# Install the npm bootstrap package
npm install -g yaver-cli
# Analyze your existing project
cd my-existing-rn-app
yaver push init
π Analyzing your project...
React Native: 0.81.5 β
(yaver supports 0.81.x)
Hermes: enabled β
New Arch: enabled β
Native modules found in your project:
react-native-screens@4.16.0 β
available in yaver
react-native-reanimated@4.1.1 β
available in yaver
react-native-gesture-handler@2.28 β
available in yaver
react-native-ble-plx@3.2.0 β NOT in yaver SDK
β
Created yaver.json
# Push to your phone
yaver push
π‘ Found: Kivanc's iPhone (192.168.1.42)
β
Compatible
π¨ Bundling for ios...
β‘ Compiling Hermes bytecode...
π€ Pushing 847 KB...
π Done in 4.1s β app loading on device
What this is NOT: Not a WebView. Every <View> renders as a real UIView / android.view.View with full New Architecture support (TurboModules, Fabric). Not Metro dev server β the phone runs a production App Store binary with 80+ pre-installed native modules.
How It Works
yaver push initreads yourpackage.json, compares against the SDK manifest (React Native version, Hermes bytecode version, native modules), and reports compatibilityyaver pushbundles your JS withreact-native bundle, compiles to Hermes bytecode with the npm package's embeddedhermesc, validates the bytecode version matches the phone app, and pushes via HTTP to the phone's on-device server (port 8347)- The phone validates the Hermes bytecode, saves it, and safely reloads the React Native bridge β polling for old bridge deallocation (Hermes GC teardown), then creating a new bridge with full New Architecture support (TurboModules, Fabric, JSI)
CLI Commands
yaver serve Start the Go agent from the npm bootstrap package
yaver push init Analyze project, show compatibility, create yaver.json
yaver push [--device <ip>] Bundle + validate + push
yaver push --watch Watch mode β re-push on file save
yaver push --ignore-missing Push even with missing native modules
yaver push doctor Deep compatibility report with fix suggestions
yaver push devices List discovered devices
yaver push modules List all SDK native modules (80+)
yaver push reset Clear pushed bundle on device
yaver push status Device + project status
yaver-push <same-subcommand> Legacy alias for existing scripts
Handling Missing Modules
If your project uses native modules not in the yaver SDK, you can still push β features using those modules will crash, but everything else works. Add graceful checks:
import { NativeModules } from 'react-native';
const isYaver = !!NativeModules.YaverInfo;
// Skip unavailable features in yaver
if (!isYaver) {
// use react-native-ble-plx normally
}
SDK Manifest
The yaver.io app now ships with 80+ pre-installed native modules including: react-native-screens, react-native-reanimated, react-native-gesture-handler, react-native-svg, react-native-webview, react-native-maps, @shopify/react-native-skia, @shopify/flash-list, @react-native-picker/picker, react-native-view-shot, expo-camera, expo-location, expo-notifications, expo-updates, and more. Run yaver push modules for the full list.
That manifest is generated from the actual mobile host app dependencies and Expo plugin config, then copied into the CLI package and embedded iOS app bundle. Regenerate with node scripts/generate-sdk-manifest.mjs and verify drift in CI with node scripts/generate-sdk-manifest.mjs --check.
Platform Support
React Native has first-class push-to-device support. Other frameworks have hot reload or build-only support.
| Platform | Push to Device | Hot Reload | Build & Upload | How |
|---|---|---|---|---|
| React Native / Expo | Yes | Yes | Yes | JS bundled + Hermes bytecode compiled + pushed to native container. Full New Arch. |
| Flutter | -- | Yes | Yes | flutter run to real device with hot reload via stdin. No container push. |
| Vite | -- | Yes | -- | Dev server proxied through P2P. Web preview on phone. |
| Next.js | -- | Yes | -- | Dev server proxied through P2P. Web preview on phone. |
| Swift / Xcode | -- | -- | Yes | xcodebuild + TestFlight upload. Full native build each time. |
| Kotlin / Gradle | -- | -- | Yes | Gradle APK/AAB build + Play Store upload. Full native build each time. |
Why React Native is special: React Native apps are JavaScript at their core. Yaver compiles your JS into Hermes bytecode and loads it into a pre-built native container on the phone -- same principle as Expo Go. Other frameworks compile to machine code (Swift, Kotlin) or use their own VM (Flutter's Dart VM), so there's no way to "inject" your app into a container without building the entire binary.
How Push to Device Works (Under the Hood)
If you've never worked with React Native internals, here's what's happening when you run yaver push:
Your Code (JSX/TypeScript)
|
v
Metro Bundler ---- combines all your files into one big JS file
|
v
Hermes Compiler (hermesc) ---- converts JS into compact bytecode (like .class files in Java)
|
v
Hermes Bytecode (.jsbundle) ---- ~60% smaller, loads 2x faster than raw JS
|
v
HTTP push to phone (port 8347) ---- sent over Wi-Fi to Yaver app
|
v
Yaver app validates + loads ---- checks bytecode version, MD5, then hot-swaps the bridge
Key concepts:
Hermes is a JavaScript engine built by Meta specifically for React Native. Instead of parsing JavaScript text at runtime (slow), Hermes pre-compiles it into bytecode (fast). Think of it like the difference between running Python source code vs. a compiled .pyc file, or Java source vs. .class bytecode.
Hermes Bytecode (HBC) is the compiled output. The file starts with a magic number (0x1F1903C1) and a version number (currently BC96 for RN 0.81). If the version in your compiled bundle doesn't match the version compiled into the phone app, it will crash -- like trying to run Java 21 bytecode on a Java 8 JVM.
The Bridge is how JavaScript talks to native code (UIKit on iOS, Android Views on Android). When you write <View>, the JS side sends a message across the bridge saying "create a native view." The native side creates a real UIView or android.view.View. This is NOT a WebView -- every component is a real native component.
New Architecture (TurboModules + Fabric) is React Native's modern runtime. Old RN used an async JSON bridge (slow). New Architecture uses JSI (JavaScript Interface) for synchronous, direct communication between JS and native -- like calling a C function from JS instead of sending a message. TurboModules are native modules that use this fast path. Fabric is the new rendering system. Yaver's container supports both.
The Native Container is Yaver's phone app with 80+ native modules pre-compiled in. When you push your JS bundle, it runs inside this container using all the pre-installed native modules (cameras, maps, sensors, storage, lists, pickers, etc.). If your app uses a native module that isn't pre-installed, that specific feature won't work, but everything else will. This is the same concept as Expo Go, but Yaver supports New Architecture and more modules.
Safe Bridge Reload -- when a new bundle arrives, Yaver can't just swap the JS file. It needs to: (1) shut down the old JavaScript runtime, (2) wait for background threads (Hermes garbage collector) to finish, (3) create a fresh runtime with the new bundle. If step 2 is skipped, the GC thread touches freed memory and the app crashes. Yaver polls for actual deallocation before proceeding.
Git Providers β Clone Repos from Your Phone
Yaver auto-detects GitHub and GitLab credentials already on your dev machine β from gh CLI, glab CLI, macOS Keychain, git credential helpers, or environment variables. No tokens ever leave the machine.
Phone (Yaver app) Dev Machine
ββββββββββββββββ ββββββββββββββββ
β Browse repos βββGET /git/reposβββββΊβ Agent queries β
β from GitHub β β GitHub/GitLab β
β or GitLab β β API with β
β βββrepo listβββββββββββ local creds β
β β β β
β Tap "Clone" βββPOST /git/cloneββββΊβ git clone β
β β β on machine β
ββββββββββββββββ ββββββββββββββββ
This is useful for headless dev machines (cloud VPS, Mac Mini) where you haven't cloned a repo yet. Browse your GitHub/GitLab repos from the app, tap clone, and the dev machine pulls it down using its own credentials. Then start coding from your phone immediately.
# Manual machine-side setup for a headless box:
yaver repo auth setup github --token <github-pat>
yaver repo auth setup gitlab --token <gitlab-pat>
yaver repo auth status
That one-time setup saves the provider token in both places Yaver uses today:
- local git credentials for private clone/pull
- vault entries (
github-token/gitlab-token) for deploy and CI helpers
Email Connectors
Connect Office 365 or Gmail for AI-assisted email workflows.
# Setup
yaver email setup # Interactive β choose Office 365 or Gmail
yaver email test # Send a test email
yaver email sync # Sync emails to local SQLite database
# Available as MCP tools: email_list_inbox, email_get, email_send, email_sync, email_search
Office 365
Requires Azure AD app registration with Microsoft Graph API permissions (Mail.Read, Mail.Send). Uses client credentials flow.
Gmail
Requires Google Cloud OAuth2 credentials with Gmail API scope. Uses refresh token flow.
Synced emails are stored locally in ~/.yaver/emails.db (SQLite) for fast search and retrieval.
ACL β Agent Communication Layer
Connect Yaver to other MCP servers for agent-to-agent workflows:
# Connect to local Ollama
yaver acl add ollama http://localhost:11434/mcp
# Connect to a filesystem MCP server (stdio)
yaver acl add files --stdio "npx -y @modelcontextprotocol/server-filesystem /home"
# Connect to a remote database
yaver acl add mydb https://db.example.com/mcp --auth token123
# List / manage peers
yaver acl list
yaver acl tools ollama
yaver acl health
yaver acl remove ollama
ACL peers are also accessible via MCP tools (acl_list_peers, acl_call_peer_tool, etc.), enabling Claude to chain tools across multiple MCP servers.
Components
| Piece | Directory | Install | What it does |
|---|---|---|---|
| Mobile App | mobile/ | App Store / Play Store | Remote control for AI agents + native RN container + on-device HTTP server (port 8347) |
| Desktop Agent | desktop/agent/ | brew install yaver or apt install yaver | Native yaver command for P2P server, AI agent runner, MCP, hot reload, builds, and session transfer. Also bridges yaver push through npm when Node is present. |
| Unified NPM Bootstrap | cli/ | npm i -g yaver-cli | Umbrella install. Installs the yaver command, bootstraps the agent, and gives you one entry point for yaver serve, yaver push, yaver feedback setup, yaver sdk add ..., and yaver install .... |
| Feedback SDKs | sdk/feedback/ | npm i -g yaver-cli then yaver feedback setup | Debug console + black box recorder embedded in your app. React Native, Flutter, Web. |
| Programmatic SDKs | sdk/ | npm i -g yaver-cli then yaver sdk add core | Automate Yaver from code β Go, Python, JS/TS, Flutter/Dart, C. |
| Desktop Installer | desktop/installer/ | Download | GUI installer (DMG/EXE/DEB) β installs the Go agent binary |
| Relay Server | relay/ | Docker / binary | QUIC relay for NAT traversal β self-hostable, pass-through only |
| Backend | backend/ | Managed (Convex) | Auth + peer discovery + platform config. No user data. |
| Web | web/ | Managed (Cloudflare Workers) | Landing page at yaver.io |
Publish Runners
Yaver can now run package and store publishes directly on developer-owned
hardware. The source of truth is project-scoped config in .yaver/publish.yaml.
That same config is surfaced through CLI, web, mobile, and MCP.
- Primary path: local/self-hosted execution on the developer's own machine.
- Yaver-first upload/register: built artifacts are archived into Yaver's own blob storage first so the system dogfoods its own uploader before any external CI or store fallback path is used.
- Optional fallback: self-hosted GitHub Actions
workflow_dispatch, only when the project allows it and the user explicitly requests it for that run. - Secret sources: Yaver vault entries and/or environment variables already present on the machine or injected by GitHub secrets/vars.
- Supported target kinds:
npm,pypi,pub.dev,testflight,playstore.
yaver publish init
yaver publish config
yaver publish run --target npm-cli
yaver publish run --target pypi-sdk-python
The repo includes .github/workflows/yaver-publish.yml for the GitHub fallback
path and exposes MCP tools publish_config_get, publish_run,
publish_submit, publish_upload, publish_ci_dispatch, publish_list, and
publish_status.
CLI Commands
yaver auth Sign in (opens browser β Apple, Google, or Microsoft)
yaver serve Start the agent
yaver mcp Start MCP server (--mode stdio|http)
yaver email Email connector (setup, test, sync, status)
yaver acl Agent Communication Layer (add, list, remove, tools, health)
yaver connect Connect to a remote agent
yaver code Terminal-first coding UX (local or remote workspace)
yaver attach Interactive terminal
yaver set-runner Set default AI agent (claude/codex/opencode/custom)
yaver relay Manage relay servers (add/remove/test β hot-reload, no restart)
yaver tunnel Manage Cloudflare Tunnels
yaver config Get/set configuration
yaver publish Project-scoped package/store publish runner
yaver status Show auth, agent, relay, and connection status
yaver doctor System health check (auth, runners, relay, network)
yaver devices List registered devices
yaver exec Execute a command on a remote device
yaver session Transfer AI agent sessions between machines
yaver handoff Pass the current AI session to Yaver (autodev takes over)
yaver build Build apps (Flutter, Gradle, Xcode, React Native)
yaver test Run tests (auto-detect framework)
yaver deploy Deploy to phone, TestFlight, Play Store, or CI
yaver debug Hot reload debug sessions
yaver repo Switch between projects
yaver vault P2P encrypted key management
yaver pipeline Build β test β deploy in one command
yaver feedback Visual bug reports (list/show/fix) β screen recording + voice from device
yaver stop Stop the agent
yaver restart Restart the agent
yaver logs View agent logs
yaver completion Generate shell completions (bash/zsh/fish)
yaver version Print version
Terminal Coding (yaver code)
yaver code is the terminal-first coding surface. It stays plain-text by default when you start from a terminal: no markdown layout, no mobile-style framing, and common terminal commands are handled locally instead of being forwarded to the runner.
# Local terminal + local repo/files on this machine
yaver code
yaver code --agent opencode --model openai/gpt-5.4
yaver code set byok openrouter --api-key $OPENROUTER_API_KEY --model openrouter/openai/gpt-5
yaver code get byok
yaver code "fix the failing tests"
# Local terminal + remote repo/files on another Yaver machine
yaver code --attach mac-mini
yaver code --attach mac-mini --username dev@example.com --agent codex --model gpt-5.4
yaver code --attach mac-mini "run tests, commit, push, and deploy the fix"
# Built-in help
yaver code help
Terminal semantics:
yaver codeandyaver code --agent ...edit the local machine's repo/files.yaver code --attach ...opens a terminal against the attached remote machine and edits that remote machine's repo/files.- Local commands such as
help,tasks,agent,clear,exit,quit,/exit, and/quitare intercepted by Yaver locally. - The plain-text terminal contract affects formatting only. The coding agent can still build, test, hot reload, commit, push, deploy, and run the normal dev loop if the target machine has the required tools and credentials.
If you want to keep the repo on one machine while borrowing runners or infra from another machine, use the yaver host-share ... borrowed-workspace flow (attach-repo, sync-repo) rather than yaver code --attach.
BYOK / OpenRouter in yaver code
yaver code can now persist a BYOK coding setup for OpenCode-backed runs instead of forcing the user to hand-edit opencode.json.
# Switch terminal coding to OpenCode + OpenRouter
yaver code set byok openrouter \
--api-key $OPENROUTER_API_KEY \
--model openrouter/openai/gpt-5
# Inspect the effective provider/model/base URL
yaver code get byok
yaver code get provider
yaver code get base-url
Notes:
- BYOK settings are tied to the current
yaver codetarget, so the same commands work against an attached remote machine too. - OpenRouter defaults to
https://openrouter.ai/api/v1. yaver code set model ...also updates the remembered provider when the model is namespaced likeopenrouter/openai/gpt-5.
Shared code control plane
The yaver code terminal is no longer the only surface that understands coding-session state.
- HTTP now exposes
/code/status,/code/attach,/code/detach,/code/repos,/code/repo,/code/dev,/code/deploy, and/code/config. - MCP exposes matching high-level tools:
code_statuscode_attachcode_detachcode_reposcode_repo_setcode_devcode_deploycode_config_getcode_config_set
- Those surfaces all operate on the same machine-aware coding state:
- current runner/model/provider
- attached machine
- active repo/workdir
- orchestration mode
- recent graph runs
- OpenCode/BYOK config when relevant
That means another coding agent can use Yaver as the control plane for multi-machine coding instead of reimplementing attach/repo/dev/deploy logic itself.
Direct deploy first, CI optional
One of Yaver's main jobs is reducing CI cost for build/test/deploy loops.
code_deployand/code/deploynow support direct host deploys from the selected repo/machine to:testflightplaystoreconvexcloudflareall
- You can override:
- repo via
repo_queryorrepo_path - executor machine via
machine - placement via
machine=auto - multi-target fan-out via
distribute=true
- repo via
- CI is still available when you want it:
ci_provider=githubci_provider=gitlab
So the default path is "deploy from owned machines directly, use CI only when it adds value", not "burn CI minutes for every internal test or staging push".
Remote task video artifacts
Tasks can optionally capture a short demo clip after they finish. This is useful when the work happened on another machine and the user wants to watch what was actually built there.
create_tasksupportsvideo_enabledandvideo_source.create_task,list_tasks, andget_taskreturn structured task objects.- When a clip exists, the task includes
videoClipId,videoStatus,videoClipUrl, andvideoPosterUrl. - The clip URL is served by the producing Yaver machine, so clients can render a watch link or an inline
<video>player.
Graph resource modes (agent_graph_start, code_mesh_start)
The graph/mesh runtime can now carry explicit self-hosted resource intent per node instead of treating every step as a generic chat task.
- MCP
agent_graph_startandcode_mesh_startaccept optional customnodes. - Each node can request
resource_modeslikebuild,deploy,browser,sim-ios,sim-android,phone,proof-video,video-summary, ortest-video. - Nodes can also carry
prior_device,prior_runner,sticky_device, andsticky_runnerso later rounds stay close to the machine/runner that already has the right repo state, build caches, devices, or credentials. - Verification-oriented nodes can set
preferred_video_modeso proof/demo clips come from the right target (browser,sim-ios,sim-android,phone). - Those fields are persisted on the graph run, shown by
agent_graph_show, and fed back into placement when the graph runs across local, remote, or borrowed shared machines.
Example:
{
"prompt": "ship the onboarding redesign",
"allowed_devices": ["mac-mini", "linux-builder"],
"nodes": [
{
"id": "build-ios",
"title": "Build iOS artifact",
"kind": "chat",
"prompt": "Implement the iOS slice and prepare a native build.",
"resource_modes": ["build", "sim-ios"],
"build_points": 1,
"prior_device": "mac-mini",
"sticky_device": true
},
{
"id": "proof",
"title": "Record proof clip",
"kind": "chat",
"depends_on": ["build-ios"],
"prompt": "Verify the flow and produce a short proof video.",
"resource_modes": ["proof-video", "video-summary", "browser"],
"preferred_video_mode": "browser",
"verify_points": 1
}
]
}
Shell Completions
# Bash β add to ~/.bashrc
eval "$(yaver completion bash)"
# Zsh β add to ~/.zshrc
eval "$(yaver completion zsh)"
# Fish
yaver completion fish | source
Voice Input & Text-to-Speech
Yaver supports voice input for both mobile and CLI β speak your tasks instead of typing.
Providers
| Provider | Type | Cost | Quality |
|---|---|---|---|
| On-device (Whisper) | Free, offline | $0 | Good (English) |
| OpenAI | Cloud, API key | $0.003/min | Excellent |
| Deepgram | Cloud, API key | $0.004/min | Excellent |
| AssemblyAI | Cloud, API key | $0.002/min | Good |
Mobile
Configure in Settings > Voice or during onboarding. Tap the mic button in the task creation modal (WhatsApp-style). Supports TTS β have responses read aloud.
CLI
# Configure speech provider
yaver config set speech.provider whisper # Free, local (requires whisper-cpp)
yaver config set speech.provider openai # Cloud (bring your own key)
yaver config set speech.api_key sk-... # Set API key
# Use voice in interactive mode
yaver connect
yaver> voice # Records, transcribes, sends as task
For local/free STT, install whisper.cpp: brew install whisper-cpp
Response Verbosity
Control how detailed AI responses are (0-10 scale):
- 0-2: Minimal β "Done, no issues"
- 3-4: Brief β 2-3 sentence summary
- 5-6: Moderate β key changes + reasoning
- 7-8: Detailed β full code changes
- 9-10: Everything β diffs, alternatives, reasoning
Set via mobile app (Settings > Voice > Response detail) or passed per-task.
SDK β Embed Yaver in Your App
Yaver provides SDKs for Go, Python, and JavaScript/TypeScript. Connect to agents, create tasks, stream output, and use speech-to-text from your own code.
Go
import yaver "github.com/kivanccakmak/yaver.io/sdk/go/yaver"
client := yaver.NewClient("http://localhost:18080", token)
task, _ := client.CreateTask("Fix the login bug", nil)
for chunk := range client.StreamOutput(task.ID, 0) {
fmt.Print(chunk)
}
Python
from yaver import YaverClient
client = YaverClient("http://localhost:18080", token)
task = client.create_task("Fix the login bug")
for chunk in client.stream_output(task["id"]):
print(chunk, end="")
JavaScript / TypeScript
import { YaverClient } from 'yaver-sdk';
const client = new YaverClient('http://localhost:18080', token);
const task = await client.createTask('Fix the login bug');
for await (const chunk of client.streamOutput(task.id)) {
process.stdout.write(chunk);
}
C/C++ (shared library)
Build the shared library, then link against it:
cd sdk/go/clib && go build -buildmode=c-shared -o libyaver.so .
#include "libyaver.h"
int client = YaverNewClient("http://localhost:18080", token);
char* result = YaverCreateTask(client, "Fix the bug", NULL);
Speech in SDK
All SDKs support speech-to-text:
# Python β transcribe audio
result = client.transcribe("recording.wav", provider="openai", api_key="sk-...")
print(result["text"])
// Go β record and transcribe
audioPath, _ := yaver.RecordAudio()
tr := yaver.NewTranscriber(&yaver.SpeechConfig{Provider: "openai", APIKey: "sk-..."})
result, _ := tr.Transcribe(audioPath)
fmt.Println(result.Text)
Feedback SDKs β Visual Bug Reports from Inside Your App
Embed in your app during development. Screen recording + voice + screenshots β sent to AI agent via P2P. Auto-disabled in production.
| SDK | Install | Trigger Modes |
|---|---|---|
| Web | npm install yaver-feedback-web | Floating button, keyboard shortcut (Ctrl+Shift+F), manual |
| React Native | npm install yaver-feedback-react-native | Shake-to-report, floating button, manual |
| Flutter | yaver_feedback: ^0.1.0 in pubspec.yaml | Shake, floating button, manual |
All SDKs include: auto device discovery, connection UI, screen recording, voice annotation, three runtime modes (Full Interactive / Semi Interactive / Post Mode), agent commentary, voice commands, and remote reload (trigger hot reload from the Yaver mobile app via the agent's command channel).
See Feedback SDK Examples for demos of each mode.
System Health Check
$ yaver doctor
Yaver Doctor
Version: 1.36.0
ββ Configuration ββ
Config file β ~/.yaver/config.json
ββ Authentication ββ
Auth token β Present
Token validation β Valid
Device ID β f5e857d3...
ββ AI Runners ββ
Claude Code (claude) β /usr/local/bin/claude (2.1.80)
OpenAI Codex (codex) ! Not installed β npm install -g @openai/codex
opencode (opencode) ! Not installed β npm install -g opencode
ββ Relay Servers ββ
Relay: My VPS β OK (89ms, password set)
ββ Network ββ
Local IP β 192.168.1.103
Internet connectivity β OK
Doctor summary: 12 passed, 3 warnings, 0 failures
Relay Server β Hot Reload
Relay servers can be added, removed, or updated while the agent is running β no restart needed.
yaver relay add https://relay.example.com --password secret --label "My VPS"
# β Agent notified β relay will connect within seconds.
yaver relay remove a4ef61ac
# β Agent notified β relay tunnel will be stopped.
yaver relay set-password newsecret
# β Agent notified β new password will be used.
yaver relay list
yaver relay test
The agent polls config every 30s as a safety net, and responds instantly to SIGHUP when relay commands run.
Relay Health Monitoring
The agent pings each relay's /health endpoint every 60 seconds. Results are cached and shown in yaver status:
Relay:
Servers:
My VPS https://relay.example.com OK (89ms, 1 tunnel(s), v0.1.0) [password]
Last check: 22s ago
Token Refresh & Re-Auth
Sessions last 30 days and auto-refresh:
- CLI: Refreshes token on startup + weekly. Detects 401 in heartbeat β warns to re-auth.
- Mobile: Refreshes on launch + every foreground resume. Auto-logouts if expired.
- Backend:
POST /auth/refreshextends session by 30 more days.
Settings (relay servers, tunnels, preferences) are preserved across sign-out/sign-in on both CLI and mobile.
Networking
Three-layer stack β no Tailscale, no TUN/TAP, no VPN rights. Application-layer only.
1. LAN Beacon (direct) ββ ~5ms ββ same WiFi, instant discovery
2. Convex IP (direct) ββ ~5ms ββ known IP from device registry
3. QUIC Relay (proxied) ββ ~50ms ββ roaming, NAT traversal
See CLAUDE.md for detailed networking architecture.
Development
cd backend && npm install && npx convex dev # Convex dev server
cd web && npm install && npm run dev # Web (localhost:3000)
cd desktop/agent && go run . serve --debug # Desktop agent
cd relay && go run . serve --password secret # Relay server (local)
Tests
# Unit tests (no external deps)
cd desktop/agent && go test -v ./...
cd relay && go test -v ./...
# Integration test suite
./scripts/test-suite.sh # Run all tests
./scripts/test-suite.sh --unit # Go unit tests only
./scripts/test-suite.sh --builds # Build verification (all platforms)
./scripts/test-suite.sh --lan # LAN direct connection (localhost)
./scripts/test-suite.sh --relay # Local relay server test
./scripts/test-suite.sh --relay-docker # Deploy relay via Docker to remote server, test, teardown
./scripts/test-suite.sh --relay-binary # Deploy relay binary to remote server, test, teardown
./scripts/test-suite.sh --tailscale # Tailscale cross-machine (local β remote server)
./scripts/test-suite.sh --cloudflare # Cloudflare tunnel test
./scripts/test-suite.sh --help # Show all options
No credentials needed: --unit, --lan, and --relay work out of the box.
Remote server tests: --relay-docker, --relay-binary, and --tailscale SSH into a remote server (e.g., Hetzner VPS) to deploy relay/agent binaries, run them, test cross-network connectivity, then tear everything down.
Credentials: Set up via .env.test (gitignored) or ../talos/.env.test:
cp .env.test.example .env.test # fill in REMOTE_SERVER_IP, etc.
For CI, store as GitHub Actions secrets. See .github/workflows/test-suite.yml.
Auth
- Apple Sign-In, Google Sign-In, Microsoft/Office 365
yaver authopenshttps://yaver.io/auth?client=desktopβ OAuth β callback tohttp://127.0.0.1:19836/callback?token=<token>
Self-Hosting
Relay Server
The relay is a lightweight QUIC proxy for NAT traversal. It's pass-through only β no data is stored. Deploy on any VPS with a public IP.
Automated Setup (recommended)
The setup script handles everything: Docker, nginx, Let's Encrypt SSL, firewall, and relay deployment.
# Prerequisites: VPS with SSH access (root), DNS A record pointing to your VPS IP
./scripts/setup-relay.sh <server-ip> <domain> --password <relay-password>
# Example
./scripts/setup-relay.sh 1.2.3.4 relay.example.com --password mysecret
# Without a domain (testing / IP-only access)
./scripts/setup-relay.sh 1.2.3.4 --no-domain --password mysecret
# Custom ports
./scripts/setup-relay.sh 1.2.3.4 relay.example.com --password secret --quic-port 5433 --http-port 9443
# Show all options
./scripts/setup-relay.sh --help
The script will:
- Install Docker on the VPS (if not present)
- Install nginx + certbot, obtain Let's Encrypt SSL certificate
- Configure nginx as HTTPS reverse proxy with SSE/streaming support
- Sparse-clone the relay directory to
/opt/yaver-relay - Build and start the relay Docker container
- Configure firewall (UFW) β TCP 443, UDP 4433, TCP 80
- Run a health check and print connection details
Manual Setup (Docker)
# On your VPS
git clone --depth 1 --filter=blob:none --sparse https://github.com/kivanccakmak/yaver.git /opt/yaver-relay
cd /opt/yaver-relay && git sparse-checkout set relay && cd relay
# Set password and start
echo "RELAY_PASSWORD=your-secret" > .env
docker compose up -d
# Verify
curl http://localhost:8443/health
# {"status":"ok"}
Manual Setup (native binary, no Docker)
# Build the relay binary (requires Go 1.22+)
cd relay
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o yaver-relay .
# Copy to server
scp yaver-relay root@<server-ip>:/usr/local/bin/yaver-relay
# On the server: run directly
RELAY_PASSWORD=your-secret yaver-relay serve --quic-port 4433 --http-port 8443
# Or install as systemd service
scp relay/deploy/yaver-relay.service root@<server-ip>:/etc/systemd/system/
ssh root@<server-ip> 'systemctl daemon-reload && systemctl enable --now yaver-relay'
HTTPS with nginx (for production)
If you set up manually (without the setup script), add nginx + Let's Encrypt for HTTPS:
# On your VPS β install nginx and certbot
apt install -y nginx certbot python3-certbot-nginx
# Get SSL certificate (point DNS A record to VPS IP first)
certbot certonly --standalone -d relay.example.com
# Copy nginx config template and edit domain
cp relay/deploy/nginx-relay.conf /etc/nginx/sites-available/yaver-relay
sed -i 's/DOMAIN/relay.example.com/g; s/HTTP_PORT/8443/g' /etc/nginx/sites-available/yaver-relay
ln -sf /etc/nginx/sites-available/yaver-relay /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# Open firewall
ufw allow 443/tcp # HTTPS
ufw allow 4433/udp # QUIC
ufw allow 80/tcp # HTTP redirect
Connect clients to your relay
# CLI β add relay to config
yaver relay add my-relay \
--quic-addr <server-ip>:4433 \
--http-url https://relay.example.com \
--password your-secret
# Or edit ~/.yaver/config.json directly
{
"relay_servers": [
{
"id": "my-relay",
"quic_addr": "<server-ip>:4433",
"http_url": "https://relay.example.com"
}
],
"relay_password": "your-secret"
}
Mobile app: Settings β Relay Servers β Add your relay URL and password.
Relay management
# Health check
curl https://relay.example.com/health
# View connected tunnels
curl https://relay.example.com/tunnels
# Logs
ssh root@<server-ip> 'cd /opt/yaver-relay/relay && docker compose logs -f' # Docker
ssh root@<server-ip> 'journalctl -u yaver-relay -f' # systemd
# Stop / remove
./relay/deploy/down.sh <server-ip> # Stop
./relay/deploy/down.sh <server-ip> --purge # Stop and remove everything
VPS requirements
- CPU/RAM: 1 vCPU, 512 MB RAM minimum (relay is very lightweight)
- Ports: TCP 443 (HTTPS), UDP 4433 (QUIC), TCP 8443 (HTTP fallback), TCP 80 (Let's Encrypt)
- OS: Any Linux with Docker (Ubuntu 22.04+ recommended)
- Providers: Hetzner, DigitalOcean, Linode, AWS Lightsail, Vultr β any VPS works
No Relay (Tailscale)
If both devices are on your Tailscale tailnet, no relay is needed:
yaver serve --no-relay # Connect directly via Tailscale IP
Tailscale client is open source (BSD 3-Clause). For a fully self-hosted alternative to the Tailscale coordination server, use Headscale.
Related Work
Projects and tools in the same problem space. Yaver is compatible with most of these and can be used alongside them. Items marked [OSS] are open-source software.
AI Coding Agents (Yaver's first-class runners)
Yaver supports exactly three coding runners. opencode wraps the long tail of providers (Anthropic / OpenAI / OpenRouter / Ollama / GLM / ZAI / β¦) via its own BYOK config, so anything you can reach from opencode you can reach from Yaver.
- Claude Code β Anthropic's agentic coding tool
- OpenAI Codex CLI
[OSS]β OpenAI's terminal coding agent - opencode
[OSS]β open-source coding agent with BYOK provider config
Local LLMs & Inference
- Ollama
[OSS]β run LLMs locally with one command - Qwen β open-weight LLMs by Alibaba Cloud
- GLM-4 β open-weight multilingual LLM
- llama.cpp
[OSS]β LLM inference in C/C++ - vLLM
[OSS]β high-throughput LLM serving engine
Remote Development
- code-server
[OSS]β VS Code in the browser - Coder
[OSS]β self-hosted remote dev environments - tmate
[OSS]β instant terminal sharing - sshx
[OSS]β collaborative terminal sharing over the web - ttyd
[OSS]β share your terminal over the web
Networking & NAT Traversal
- Tailscale β mesh VPN built on WireGuard (client is open-source)
- NetBird
[OSS]β network connectivity platform - frp
[OSS]β fast reverse proxy for NAT traversal - Cloudflare Tunnel β expose local services securely
- Headscale
[OSS]β self-hosted Tailscale control server
Infrastructure & Protocols
- Convex β reactive backend-as-a-service (runtime is open-source)
- quic-go
[OSS]β QUIC protocol implementation in Go - tmux
[OSS]β terminal multiplexer - MCP
[Open Spec]β Model Context Protocol - QUIC (RFC 9000)
[Open Standard]β UDP-based transport protocol - WireGuard
[OSS]β modern VPN protocol
Security
- Reporting a vulnerability: email
kivanc.cakmak@simkab.com. 48-hour acknowledgement, 90-day disclosure window, good-faith safe harbour. Do not open a public GitHub issue for security bugs. Full policy:SECURITY.md. - Production is protected by a 5-layer defence: required reviewer on
the
Productionenvironment, branch + tag allowlist on that environment,mainbranch ruleset (no force-push, linear history, signed commits), release-tag ruleset (only admin can create/update),CODEOWNERSgating all CI / deploy / auth / vault code, and fork PRs are blocked from reading secrets. SeeSECURITY.mdΒ§"How production is protected" for the full breakdown. - Contributors: sign off every commit with
git commit -s(DCO). Commits onmainfrom the repo owner are GPG-signed β unsigned commits by the owner name are a signal to investigate.
Legal
Developed by SIMKAB ELEKTRIK β Istanbul, Turkey
Contact: kivanc.cakmak@simkab.com
License
Yaver uses a split-license model β see LICENSING.md
for the full mapping and CONTRIBUTING.md for how
contributions are licensed.
- Core (agent, relay, backend, web UI, mobile app, desktop
app/installer, pi-image) β
FSL-1.1-Apache-2.0: Functional Source License. Free for any non-competing use; each release auto-transitions to Apache-2.0 two years after publication. - Client SDKs & CLIs (
cli/,sdk/js,sdk/feedback/*,sdk/flutter,sdk/python,sdk/go/*,sdk/errors-js) β Apache-2.0 from day one, embed in closed-source apps freely.
Rule of thumb: does your app import / bundle / invoke this code? Yes β Apache-2.0. No, it's a network service β FSL-1.1-Apache-2.0.
A commercial license is available for organizations that need the core without the Competing Use restriction β contact kivanc.cakmak@simkab.com.
