For cross-project context (how this project relates to other Kyle projects), see ~/code/dotfiles/projects/README.md.
A mobile-first supervisor for Claude Code agents. Like the VS Code Claude extension, but designed for phones and multi-session workflows.
Key ideas:
- Server-owned processes — Claude runs on your dev machine; client disconnects don't interrupt work
- Multi-session dashboard — See all projects at a glance, no window cycling
- Mobile supervision — Push notifications for approvals, respond from your lock screen
- Zero external dependencies — No Firebase, no accounts
Architecture: Hono server manages Claude SDK processes. React client connects via WebSocket for real-time streaming. Sessions persist to jsonl files (handled by SDK).
Remote access: Two connection modes:
- Direct (Tailscale/LAN) — Client connects to server WebSocket directly
- Relay — Client connects through a relay server (
packages/relay/). SRP (Secure Remote Password) authenticates without exposing the password to the relay. All messages are end-to-end encrypted with NaCl (XSalsa20-Poly1305) so the relay sees only opaque ciphertext.
For detailed overview, see docs/project/. Historical vision docs in docs/archive/.
All ports are derived from a single PORT environment variable (default: 3400):
| Port | Purpose |
|---|---|
| PORT + 0 | Main server (default: 3400) |
| PORT + 1 | Maintenance server (default: 3401) |
| PORT + 2 | Vite dev server (default: 3402) |
To run on different ports:
PORT=4000 pnpm dev # Uses 4000, 4001, 4002Individual overrides (rarely needed):
MAINTENANCE_PORT- Override maintenance port (set to 0 to disable)VITE_PORT- Override vite dev port
Server state is stored in a data directory (default: ~/.yep-anywhere/). This includes:
logs/- Server logsindexes/- Session index cacheuploads/- Uploaded filessession-metadata.json- Custom titles, archive/starred statusnotifications.json- Last-seen timestampspush-subscriptions.json- Web push subscriptionsvapid.json- VAPID keys for pushauth.json- Authentication state (password hash, sessions)
Use profiles to run dev and production instances simultaneously (like Chrome profiles):
# Production (default profile, port 3400)
PORT=3400 pnpm start
# Development (dev profile, port 4000)
PORT=4000 YEP_ANYWHERE_PROFILE=dev pnpm devThis creates separate data directories:
- Production:
~/.yep-anywhere/ - Development:
~/.yep-anywhere-dev/
Environment variables:
YEP_ANYWHERE_PROFILE- Profile name suffix (creates~/.yep-anywhere-{profile}/)YEP_ANYWHERE_DATA_DIR- Full path override for data directoryCLAUDE_CONFIG_DIR- Claude Code config directory (default:~/.claude). Use this to point at a Claude Code profile (e.g.,~/.claude-work). Sessions are scanned from{CLAUDE_CONFIG_DIR}/projects/.
Note: By default, all instances share ~/.claude/projects/ (SDK-managed sessions). Set CLAUDE_CONFIG_DIR to use a different Claude Code profile per instance.
Restrict which agent providers and features are available:
# Only show Claude Code (hide Codex, Gemini, etc.)
ENABLED_PROVIDERS=claude pnpm dev
# Disable voice input (microphone button)
VOICE_INPUT=false pnpm dev
# Combined example: Claude-only, no voice, dev profile
ENABLED_PROVIDERS=claude VOICE_INPUT=false PORT=4000 YEP_ANYWHERE_PROFILE=dev pnpm devEnvironment variables:
ENABLED_PROVIDERS- Comma-separated list of provider names to expose (default: all). Valid names:claude,claude-ollama,codex,codex-oss,gemini,gemini-acp,opencodeVOICE_INPUT- Set tofalseto disable the voice input button server-side (default:true)
Always use the Android emulator to test when it's available. Check with source ~/.profile && adb devices and deploy/test on the emulator whenever possible.
Use the claw-starter browser skill at ~/code/claw-starter to automate browser-based testing of the web UI. This uses Playwright with headless Chromium.
Start the browser server (if not already running):
cd ~/code/claw-starter && npx tsx lib/browser/server.ts &CLI commands (run from ~/code/claw-starter):
npx tsx lib/browser-cli.ts status # Check if server is running
npx tsx lib/browser-cli.ts open <url> # Open URL in new tab
npx tsx lib/browser-cli.ts navigate <url> # Navigate current tab
npx tsx lib/browser-cli.ts snapshot --efficient # Read page (accessibility tree)
npx tsx lib/browser-cli.ts screenshot # Take screenshot (returns path)
npx tsx lib/browser-cli.ts click e5 # Click element by ref
npx tsx lib/browser-cli.ts type e5 "text" # Type into element
npx tsx lib/browser-cli.ts evaluate "JS expr" # Run JS and return result
npx tsx lib/browser-cli.ts tabs # List open tabs
npx tsx lib/browser-cli.ts close # Close tabWorkflow: snapshot → act (click/type) using element refs → snapshot again to verify.
See ~/code/claw-starter/README.md for the full CLI reference.
For Chromebook testing and debugging (screenshots, input, diagnostics), use the chromeos-testbed CLI — NOT the browser control skill (which is for local headless Chromium).
~/code/chromeos-testbed/bin/chromeos screenshot # saves screenshot, prints path
~/code/chromeos-testbed/bin/chromeos screenshot output.png # saves to output.png
~/code/chromeos-testbed/bin/chromeos help # full command listRequires SSH access to chromeroot. See ~/code/chromeos-testbed/CLAUDE.md for details.
After editing TypeScript or other source files, verify your changes compile and pass checks:
pnpm lint # Biome linter
pnpm typecheck # TypeScript type checking (fast, no emit)
pnpm test # Unit tests
pnpm test:e2e # E2E tests (if UI changes)For site changes (marketing pages in site/):
cd site && npm run build # Astro check + build (or: pnpm site:build from root)Fix any errors before considering the task complete.
Periodically run pnpm audit --prod and pay special attention to the web-push -> asn1.js -> bn.js chain. Keep bn.js patched (currently via pnpm override) until web-push ships an upstream fix.
Never mention Claude, AI, or any AI assistant in commit messages. Write commit messages as if a human developer wrote them.
The package is published to npm as yepanywhere using GitHub Actions with OIDC trusted publishing (no npm tokens stored in secrets).
Before releasing:
-
Update
CHANGELOG.mdwith a new version section:## [0.1.11] - 2025-01-24 ### Added - New feature description ### Fixed - Bug fix description
-
Commit the changelog update
-
Tag and push:
git tag v0.1.11 git push origin v0.1.11
The CI workflow verifies the changelog contains an entry for the version being released. If missing, the release will fail with instructions to update the changelog.
The workflow runs lint, typecheck, and tests, then builds with pnpm build:bundle and publishes with --provenance for supply chain attestation. It also creates a GitHub Release with auto-generated notes.
The website (landing pages + remote relay client at /remote) is deployed to GitHub Pages separately from npm. Pushing to main does NOT deploy the site — it only runs CI (lint, typecheck, tests). The site only deploys when a site-v* tag is pushed (or via manual workflow_dispatch).
See site/RELEASING.md for the full process.
Quick reference:
# Update site/CHANGELOG.md first, then:
scripts/release-website.sh 1.5.3Server logs are written to {dataDir}/logs/ (default: ~/.yep-anywhere/logs/):
server.log- Main server log (dev mode withpnpm dev)e2e-server.log- Server log during E2E tests
To view logs in real-time: tail -f ~/.yep-anywhere/logs/server.log
All console.log/error/warn output is captured. Logs are JSON format in the file but pretty-printed to console.
Environment variables:
LOG_DIR- Custom log directoryLOG_FILE- Custom log filename (default: server.log)LOG_LEVEL- Minimum level: fatal, error, warn, info, debug, trace (default: info)LOG_FILE_LEVEL- Separate level for file logging (default: same as LOG_LEVEL)LOG_TO_FILE- Set to "true" to enable file logging (default: off)LOG_PRETTY- Set to "false" to disable pretty console logs (default: on)
Remote collection of browser console.log/warn/error from mobile clients. Useful for debugging connection issues on devices where you can't open DevTools.
Enable: Developer Mode settings → "Remote Log Collection" toggle.
Storage: {dataDir}/logs/client-logs/ (default: ~/.yep-anywhere/logs/client-logs/). One JSONL file per device per day, named client-{YYYY-MM-DD}-{deviceId}.jsonl. The device UUID is persisted in the client's localStorage.
Each line is a single log event:
{"timestamp":1770790157738,"level":"log","prefix":"[SecureConnection]","message":"[SecureConnection] Closed: 1006","_receivedAt":1770790161477}A [ClientInfo] entry is written on each session start with user agent, screen size, DPR, and language.
# List device log files
ls ~/.yep-anywhere/logs/client-logs/
# View today's logs for a device
cat ~/.yep-anywhere/logs/client-logs/client-$(date +%Y-%m-%d)-<deviceId>.jsonl
# Follow incoming logs
tail -f ~/.yep-anywhere/logs/client-logs/*.jsonlImplementation: packages/client/src/lib/diagnostics/ClientLogCollector.ts (client), packages/server/src/routes/client-logs.ts (server POST /api/client-logs).
A separate lightweight HTTP server runs on PORT + 1 (default 3401) for out-of-band diagnostics. Useful when the main server is unresponsive.
# Check server status
curl http://localhost:3401/status
# Enable proxy debug logging at runtime
curl -X PUT http://localhost:3401/proxy/debug -d '{"enabled": true}'
# Change log levels at runtime
curl -X PUT http://localhost:3401/log/level -d '{"console": "debug"}'
# Enable Chrome DevTools inspector
curl -X POST http://localhost:3401/inspector/open
# Then open chrome://inspect in Chrome
# Trigger server restart
curl -X POST http://localhost:3401/reloadAvailable endpoints:
GET /health- Health checkGET /status- Memory, uptime, connectionsGET|PUT /log/level- Get/set log levelsGET|PUT /proxy/debug- Get/set proxy debug loggingGET /inspector- Inspector statusPOST /inspector/open- Enable Chrome DevToolsPOST /inspector/close- Disable Chrome DevToolsPOST /reload- Restart server
Environment variables:
MAINTENANCE_PORT- Port for maintenance server (default: PORT + 1, set to 0 to disable)PROXY_DEBUG- Enable proxy debug logging at startup (default: false)
Validate JSONL session files against Zod schemas:
# Validate all sessions in ~/.claude/projects
npx tsx scripts/validate-jsonl.ts
# Validate a specific file or directory
npx tsx scripts/validate-jsonl.ts /path/to/session.jsonlRun this after schema changes to verify compatibility with existing session data.
Validate tool_use_result fields from SDK raw logs against ToolResultSchemas:
# Validate sdk-raw.jsonl (default location)
npx tsx scripts/validate-tool-results.ts
# Summary only (no error details)
npx tsx scripts/validate-tool-results.ts --summary
# Filter by tool name
npx tsx scripts/validate-tool-results.ts --tool=EditThe SDK provides structured tool_use_result objects alongside tool results. These are logged to ~/.yep-anywhere/logs/sdk-raw.jsonl when LOG_SDK_MESSAGES=true is set. Run this script after adding new tool schemas or when debugging tool result parsing.
Types are defined in packages/shared/src/claude-sdk-schema/ (Zod schemas as source of truth).
Key patterns:
- Message identification: Use
getMessageId(m)helper which returnsuuid ?? id - Content access: Prefer
message.contentover top-levelcontent - Type discrimination: Use
typefield (user/assistant/system/summary)