openclaw-voice
v1.0.6
Published

Readme
OpenClaw Voice

Voice-first OpenClaw experience for mobile and code.
Speak -> edit -> send -> stream response.
Why OpenClaw Voice
- Fast voice-to-chat workflow optimized for iOS
- Reusable
GatewayClientSDK on npm (openclaw-voice) - Streaming + recovery handling for unstable mobile networks
- Secure device identity signing via Ed25519
Run The App (5 Minutes)
Prerequisites:
- Node.js 18+
- Xcode + iOS runtime
- CocoaPods
- Android Studio + Android SDK (for Android runs)
- A running OpenClaw Gateway endpoint (
wss://...)
Quick setup:
npm run setupOptional environment check:
npm run doctor:iosDebug run path (development, Metro required):
# Terminal A
npm run dev:metro
# Terminal B
npm run ios:dev:device:installIf Connecting to: iPhone keeps spinning forever, stop that terminal (Ctrl+C) and launch directly:
EXPO_DEV_SERVER_URL=<metro-url> npm run ios:dev:device:openRelease run path (device testing, Metro not required):
npm run ios:release:devicescripts/bootstrap.sh runs npm run setup and prints these run paths.
Android run path:
npm run doctor:android
npm run android:emulator:setup # one-time
npm run android:emulator:start # start emulator
npm run androidIf doctor:android reports SDK errors, set ANDROID_HOME (or ANDROID_SDK_ROOT) and ensure adb is available.
If AVD creation fails with Valid system image paths are: null, install cmdline-tools;latest inside your SDK and rerun npm run android:emulator:setup.
Android: Verified Device/Emulator Steps
Verified on macOS with Expo SDK 54 and Android API 35.
- Set SDK environment variables:
export ANDROID_HOME="$HOME/Library/Android/sdk"
export ANDROID_SDK_ROOT="$ANDROID_HOME"
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$ANDROID_HOME/cmdline-tools/latest/bin:$PATH"- Validate toolchain:
npm run doctor:android- Emulator path:
npm run android:emulator:setup
npm run android:emulator:start
npm run android- Physical device path (USB debugging enabled):
adb devices
npm run androidExpected result:
adb devicesshows at least onedevice- Expo installs and launches the app without SDK-path errors
What Is Metro?
Metro is the JavaScript bundler/dev server used by React Native/Expo in development.
In Debug builds, the app loads JS from Metro (usually :8081) with fast refresh.
- Debug build (
npm run ios,npm run ios:dev) -> Metro required - Release build (
--configuration Release) -> Metro not required (bundle is embedded)
If Debug app does not attach to Metro, pass URL explicitly:
EXPO_DEV_SERVER_URL=http://192.168.0.10:8081 npm run ios:dev:device:openUse It As npm Package
Install:
npm install openclaw-voiceExample:
import { GatewayClient, setStorage } from 'openclaw-voice';
// Optional: set persistent storage for device identity.
setStorage({
getString: (key) => localStorage.getItem(key) ?? undefined,
set: (key, value) => localStorage.setItem(key, value),
});
const client = new GatewayClient('wss://your-openclaw-gateway.example.com', {
token: 'your-token',
clientId: 'openclaw-ios',
displayName: 'OpenClaw Pocket',
role: 'operator',
scopes: ['operator.read', 'operator.write'],
caps: ['talk'],
});
client.onConnectionStateChange((state) => console.log('connection:', state));
client.onChatEvent((event) => console.log('chat event:', event.state, event.message));
await client.connect();
const result = await client.chatSend('demo-session-1', 'Hello from openclaw-voice');
console.log('runId:', result.runId);Notes:
- Without
setStorage, identity is in-memory and may require re-pairing after restart. - In React Native/Expo, load crypto/base64 polyfills before using the client when needed.
Screenshots
Features
- Voice input with hold-to-record (
expo-speech-recognition) - Editable transcript and quick text insert buttons
- Speech language switch (
ja-JP/en-US) - Dedicated Settings screen and Sessions screen
- Session management: list, switch, rename, pin/unpin, create
- Gateway connect/reconnect flow with startup auto-connect retry
- History sync and manual refresh with status notice
- Streaming response rendering with per-turn states (
WAIT,OK,ERR) - Markdown response rendering with URL linkification
- Persistent local settings and secure local device identity reuse
Environment Variables
Copy .env.example to .env:
cp .env.example .envEXPO_PUBLIC_DEFAULT_GATEWAY_URLEXPO_PUBLIC_DEFAULT_THEME(lightordark)EXPO_PUBLIC_DEFAULT_SESSION_KEY(default:main)EXPO_PUBLIC_GATEWAY_CLIENT_ID(default:openclaw-ios)EXPO_PUBLIC_GATEWAY_DISPLAY_NAME(default:OpenClaw Pocket)EXPO_PUBLIC_DEBUG_MODE(trueto show dev warnings and runtime debug panel, default:false)
Connection Defaults
clientId: openclaw-iosdisplayName: OpenClaw Pocketrole: operatorscopes: operator.read, operator.writecaps: talk
Device identity is generated locally and reused when persistent storage is available.
Scripts
npm run setup- Install deps, prepare native iOS project, install Podsnpm run doctor:ios- Validate iOS development environment and connectivitynpm run doctor:android- Validate Android SDK/adb/device environmentnpm run android:emulator:setup- Install Android SDK pieces and create default emulator (Pixel_8_API_35)npm run android:emulator:start- Start default Android emulatornpm run dev:metro- Start Metro for dev-client (tunnel mode)npm run start- Start Expo dev servernpm run ios- Alias fornpm run ios:devnpm run ios:dev- Build and run iOS Debug app (Metro required)npm run ios:dev:device- Build and run iOS Debug app on device (Metro required)npm run ios:dev:device:install- Install iOS Debug app on device (no bundler startup)npm run ios:dev:device:open- Launch installed iOS app on connected device (usesEXPO_DEV_SERVER_URLwhen set)npm run ios:release- Build and run iOS Release app (Metro not required)npm run ios:release:device- Build and run iOS Release app on device (Metro not required)npm run android- Build and run Android appnpm run web- Run web targetnpm run typecheck- Run TypeScript checksnpm run lint- Run repository lint checksnpm test- Run regression tests (runtime logic + manifest switch)npm run smoke:pack-install- Pack tarball and verify install/import from a clean temp appnpm run build:package- Build npm package files todist/
Local Quality Checks
Run before opening a PR:
npm run typecheck
npm run lint
npm test
npm run smoke:pack-installIf your environment cannot access npm network during smoke test:
OPENCLAW_SMOKE_SKIP_INSTALL=1 npm run smoke:pack-installSecurity Notes
- Do not commit private gateway tokens.
- Use secure
wss://endpoints. - Preferred exposure path order: Tailscale/WireGuard -> Cloudflare Tunnel + access control -> Hardened VPS reverse proxy.
- Do not expose raw Gateway ports publicly.
- Rotate credentials and keep TLS/server packages up to date.
Funding
If this project helps your workflow, you can support maintenance on GitHub Sponsors:
Troubleshooting
For No script URL provided / Could not connect to development server:
- Start Metro explicitly (
npx expo start --dev-client --host tunnel --clear) - Reinstall Debug app with
--no-bundlerfrom another terminal - Or use Release build (
npx expo run:ios --device --configuration Release)
See docs/TROUBLESHOOTING.md for more.
Contributing
See CONTRIBUTING.md.
CI
GitHub Actions runs on push/PR:
- Type check (
npm run typecheck) - Package dry-run (
npm pack --dry-run) - Manifest restore check after pack (
package.json.mainstaysindex.ts) - Lint (
npm run lint) - Tests (
npm test) - Tarball install smoke test (
npm run smoke:pack-install)
Issue/PR templates are in .github/.
Publish to npm
This repo uses two entry contexts:
- App runtime:
package.json.main = index.ts - npm package tarball:
main = ./dist/package.js(switched automatically during pack/publish)
Release steps:
npm version patch --no-git-tag-version
git add package.json package-lock.json
git commit -m "chore(release): bump version to x.y.z"
# Runs prepack/postpack hooks automatically:
# - prepack: build + switch manifest for package publish
# - postpack: restore app manifest
npm publish --access public
git tag vX.Y.Z
git push -u origin main
git push origin vX.Y.ZAcknowledgements
License
MIT. See LICENSE.
