Skip to content

Latest commit

 

History

History
327 lines (225 loc) · 12.4 KB

CLAUDE.md

File metadata and controls

327 lines (225 loc) · 12.4 KB

Yep Anywhere

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/.

Port Configuration

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, 4002

Individual overrides (rarely needed):

  • MAINTENANCE_PORT - Override maintenance port (set to 0 to disable)
  • VITE_PORT - Override vite dev port

Data Directory & Profiles

Server state is stored in a data directory (default: ~/.yep-anywhere/). This includes:

  • logs/ - Server logs
  • indexes/ - Session index cache
  • uploads/ - Uploaded files
  • session-metadata.json - Custom titles, archive/starred status
  • notifications.json - Last-seen timestamps
  • push-subscriptions.json - Web push subscriptions
  • vapid.json - VAPID keys for push
  • auth.json - Authentication state (password hash, sessions)

Running Multiple Instances

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 dev

This 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 directory
  • CLAUDE_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.

Provider & Feature Configuration

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 dev

Environment variables:

  • ENABLED_PROVIDERS - Comma-separated list of provider names to expose (default: all). Valid names: claude, claude-ollama, codex, codex-oss, gemini, gemini-acp, opencode
  • VOICE_INPUT - Set to false to disable the voice input button server-side (default: true)

Android Emulator Testing

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.

Browser Control (UI Testing)

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 tab

Workflow: snapshot → act (click/type) using element refs → snapshot again to verify.

See ~/code/claw-starter/README.md for the full CLI reference.

ChromeOS Debugging

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 list

Requires SSH access to chromeroot. See ~/code/chromeos-testbed/CLAUDE.md for details.

After Editing Code

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.

Dependency Security Maintenance

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.

Git Commits

Never mention Claude, AI, or any AI assistant in commit messages. Write commit messages as if a human developer wrote them.

Releasing to npm

The package is published to npm as yepanywhere using GitHub Actions with OIDC trusted publishing (no npm tokens stored in secrets).

Before releasing:

  1. Update CHANGELOG.md with a new version section:

    ## [0.1.11] - 2025-01-24
    
    ### Added
    - New feature description
    
    ### Fixed
    - Bug fix description
  2. Commit the changelog update

  3. 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.

Releasing the Website

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.3

Server Logs

Server logs are written to {dataDir}/logs/ (default: ~/.yep-anywhere/logs/):

  • server.log - Main server log (dev mode with pnpm 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 directory
  • LOG_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)

Client Console Logs

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/*.jsonl

Implementation: packages/client/src/lib/diagnostics/ClientLogCollector.ts (client), packages/server/src/routes/client-logs.ts (server POST /api/client-logs).

Maintenance Server

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/reload

Available endpoints:

  • GET /health - Health check
  • GET /status - Memory, uptime, connections
  • GET|PUT /log/level - Get/set log levels
  • GET|PUT /proxy/debug - Get/set proxy debug logging
  • GET /inspector - Inspector status
  • POST /inspector/open - Enable Chrome DevTools
  • POST /inspector/close - Disable Chrome DevTools
  • POST /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)

Validating Session Data

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.jsonl

Run this after schema changes to verify compatibility with existing session data.

Validating Tool Results

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=Edit

The 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.

Type System

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 returns uuid ?? id
  • Content access: Prefer message.content over top-level content
  • Type discrimination: Use type field (user/assistant/system/summary)