home / skills / trentshaines / dotfiles / trent-local-voice-server-prod

trent-local-voice-server-prod skill

/dot_claude/skills/trent-local-voice-server-prod

This skill helps you deploy and test a local voice development server with ngrok, coordinating backend, frontend, and voice services.

npx playbooks add skill trentshaines/dotfiles --skill trent-local-voice-server-prod

Review the files below or copy the command above to add this skill to your agents.

Files (1)
skill.md
3.7 KB
---
name: trent-local-voice-server-prod
description: Deploy the local voice development server with ngrok for outbound calling. Use when the user asks to test voice locally, start the voice server, or debug voice calls.
---

# Local Voice Server Deployment (Production)

Deploy the local voice development server with ngrok tunnel for outbound calling. This runs:
1. ngrok (to expose voice server to internet)
2. Voice server (port 8080, with ngrok URL)
3. Backend server (port 8000)
4. Frontend (port 3000)

## Manual Steps (if running without tmux automation)

1. Start ngrok: `ngrok http 8080`
2. Get URL: `curl -s http://localhost:4040/api/tunnels | jq -r '.tunnels[0].public_url'`
3. Voice server: `DECAGON_ENV=prod VOICE_OUTBOUND_BASE_URL=<ngrok-url> uvicorn backend.server_cs.voice_server:app --reload --port 8080`
4. Backend: `DECAGON_ENV=prod uvicorn backend.server_cs.server:app --reload --port 8000`
5. Frontend: `cd frontend && DECAGON_ENV=prod yarn run dev --webpack`

## Full Script (Automated 2x2 Layout)

Creates 4 NEW panes (leaves Claude Code pane untouched):
```
[Claude] | [ngrok]   | [backend]
         | [voice]   | [frontend]
```

```bash
# Create 4 NEW panes - don't touch the original Claude Code pane
# 1. Split right for ngrok
NGROK_PANE=$(tmux split-window -h -P -F '#{pane_id}')

# 2. Split ngrok down for voice
VOICE_PANE=$(tmux split-window -v -t "$NGROK_PANE" -P -F '#{pane_id}')

# 3. Split ngrok right for backend
BACKEND_PANE=$(tmux split-window -h -t "$NGROK_PANE" -P -F '#{pane_id}')

# 4. Split voice right for frontend
FRONTEND_PANE=$(tmux split-window -h -t "$VOICE_PANE" -P -F '#{pane_id}')

# Layout is now:
# [Claude] | [ngrok]   | [backend]
#          | [voice]   | [frontend]

# 5. Start ngrok
tmux send-keys -t "$NGROK_PANE" 'ngrok http 8080' Enter

# 6. Wait for ngrok to initialize
sleep 4

# 7. Get ngrok URL (retry if needed)
for i in 1 2 3 4 5; do
  NGROK_URL=$(curl -s http://localhost:4040/api/tunnels 2>/dev/null | jq -r '.tunnels[0].public_url' 2>/dev/null)
  if [ -n "$NGROK_URL" ] && [ "$NGROK_URL" != "null" ]; then
    break
  fi
  sleep 2
done

if [ -z "$NGROK_URL" ] || [ "$NGROK_URL" = "null" ]; then
  echo "ERROR: Could not get ngrok URL. Check if ngrok is running."
  exit 1
fi

echo "ngrok URL: $NGROK_URL"

# 8. Start voice server (with ngrok URL) - use 'env' for fish shell compatibility
tmux send-keys -t "$VOICE_PANE" "env DECAGON_ENV=prod VOICE_OUTBOUND_BASE_URL=$NGROK_URL uvicorn backend.server_cs.voice_server:app --reload --port 8080" Enter

# 9. Start backend - use 'env' for fish shell compatibility
tmux send-keys -t "$BACKEND_PANE" 'env DECAGON_ENV=prod uvicorn backend.server_cs.server:app --reload --port 8000' Enter

# 10. Start frontend - use 'env' for fish shell compatibility
tmux send-keys -t "$FRONTEND_PANE" 'cd frontend && env DECAGON_ENV=prod yarn run dev --webpack' Enter

echo "Voice development environment started!"
echo "ngrok URL: $NGROK_URL"
echo ""
echo "Layout:"
echo "  [Claude] | [ngrok]   | [backend]"
echo "           | [voice]   | [frontend]"
echo ""
echo "To test: Go to http://localhost:3000 -> Preview -> Voice -> Enter phone # and select agent"
```

## Prerequisites

- ngrok installed and authenticated (`ngrok config add-authtoken <token>`)
- tmux running
- jq installed (for parsing ngrok API response)

## Expected Result

- ngrok tunnel running, exposing port 8080
- Voice server at http://localhost:8080 (with VOICE_OUTBOUND_BASE_URL set)
- Backend at http://localhost:8000
- Frontend at http://localhost:3000
- Test via: Preview -> Voice -> Enter phone # & select voice agent

## Notes

- This is for **outbound calling** without Twilio webhook setup
- For inbound calling, you need to update the webhook URL in Twilio
- The ngrok URL changes each time unless you have a paid ngrok plan with reserved domains

Overview

This skill deploys a local production-mode voice development environment using ngrok for outbound calling. It orchestrates ngrok, a voice server, backend, and frontend in a tmux layout so you can test voice flows from your local machine. Use it to quickly expose the voice server to the internet and run the full stack together for debugging and manual tests.

How this skill works

The script creates four new tmux panes and starts ngrok to expose port 8080. It reads the ngrok public URL, injects that as VOICE_OUTBOUND_BASE_URL, then launches the voice server on port 8080, backend on 8000, and frontend on 3000. The process uses environment variables for prod mode and retries to fetch the ngrok URL before failing.

When to use it

  • You need to test outbound voice calls from your local development environment.
  • You want a reproducible tmux layout that runs ngrok, voice server, backend, and frontend together.
  • You need to debug voice call flows that require an externally reachable callback URL.
  • You want to run the full stack locally in production mode for QA or demo purposes.

Best practices

  • Install and authenticate ngrok, run tmux, and install jq before using the script.
  • Use a paid ngrok plan or reserved domain if you need a stable public URL across sessions.
  • Keep sensitive credentials out of logs and environment variables when sharing output.
  • Run the script from the repository root so relative frontend path resolution (cd frontend) works.
  • If ngrok URL fetch fails, open the ngrok web UI at http://localhost:4040 to inspect tunnels.

Example use cases

  • Start the local voice environment to confirm outbound call routing and audio playback.
  • Quickly reproduce a voice-related bug by running the exact prod-mode services locally.
  • Demo voice agent interactions to stakeholders using the local frontend and ngrok tunnel.
  • Develop and test integration logic that depends on the voice server's outbound callbacks.

FAQ

What prerequisites are required?

Install and authenticate ngrok, have tmux running, and install jq for parsing the ngrok API response.

Why does the ngrok URL change each run?

Free ngrok tunnels generate ephemeral URLs. Use a paid plan with reserved domains to keep a stable URL.