Files
EvoScientist/docs/deployment-macos-24h.md
T
Jiao Huifeng 28f0d15cda docs: add macOS 24/7 deployment guide for EvoSci + ccproxy + Telegram STT bot (#32)
Comprehensive step-by-step guide covering:
- ccproxy installation from source (patched fork required for Claude 4+)
- ccproxy OAuth login via `ccproxy auth login claude-api`
- EvoScientist install with telegram + stt extras using uv
- STT model pre-download to avoid first-message delay
- launchd plist setup for auto-start on login with KeepAlive
- Full troubleshooting section based on real deployment experience:
  - OAuth token not found (.credentials.json location)
  - Packages installed in wrong Python environment (conda vs .venv)
  - Shell glob eating brackets in pip install 'pkg[extra]'
  - Whisper hallucination / VAD filter
  - ffmpeg approval prompts → --auto-approve
  - heredoc variable expansion gotcha
  - External drive mount timing with launchd

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Xi Zhang <106144707+X-iZhang@users.noreply.github.com>
2026-03-19 18:45:34 +00:00

9.3 KiB

Running EvoScientist 24/7 on macOS (Telegram Bot + STT + ccproxy)

This guide covers deploying EvoScientist as a fully automated 24/7 service on macOS (tested on Mac Mini with Apple Silicon), using:

  • EvoScientist — the AI research agent
  • ccproxy — local proxy that routes API calls through your Claude Code subscription
  • Telegram channel — messaging interface
  • STT — automatic voice message transcription (faster-whisper)

Prerequisites

  • macOS 13+ (Apple Silicon or Intel)
  • Claude Code installed and subscription active
  • uv installed
  • A Telegram bot token (from @BotFather)
  • Your Telegram user ID (from @userinfobot)

1. Clone repositories

mkdir -p ~/Dev/tools
cd ~/Dev/tools

git clone git@github.com:jhfnetboy/EvoScientist.git
git clone git@github.com:jhfnetboy/ccproxy-api.git

Both repos should sit as siblings in the same parent directory.


2. Install ccproxy from source

Do not pip install ccproxy-api from PyPI — it lacks the adaptive thinking and OAuth header fixes required for Claude 4+ models. Install from the patched fork.

cd ~/Dev/tools/ccproxy-api
git checkout jhf-research
pip install -e .
which ccproxy   # verify: should print a path

3. Authenticate ccproxy with your Claude subscription

This step opens a browser window to log in with your Claude account. It only needs to be done once per machine.

ccproxy auth login claude-api

Verify the token was saved:

ls ~/.claude/.credentials.json   # note the leading dot

4. Install EvoScientist from source

cd ~/Dev/tools/EvoScientist
git checkout jhf-research

# Install with Telegram and STT support
uv pip install -e '.[telegram,stt]'

Important: always use uv pip install, not pip install, to ensure packages land in the correct .venv that the service will use.

Verify:

which EvoSci
EvoSci -h

5. Pre-download the STT model

The STT model (~250 MB) downloads from HuggingFace on first use. Pre-download it now to avoid a delay on the first voice message:

uv run python -c "
from faster_whisper import WhisperModel
WhisperModel('Systran/faster-whisper-small', device='cpu', compute_type='int8')
print('STT model ready')
"

6. Configure EvoScientist

cd ~/Dev/tools/EvoScientist

EvoSci config set anthropic_base_url "http://localhost:8000/claude"
EvoSci config set anthropic_api_key  "sk-dummy"
EvoSci config set model              "claude-sonnet-4-6"

# Telegram
EvoSci config set telegram_bot_token      "YOUR_BOT_TOKEN"
EvoSci config set telegram_allowed_senders "YOUR_TELEGRAM_USER_ID"

# STT voice transcription
EvoSci config set stt_enabled  true
EvoSci config set stt_language zh     # zh / en / auto

# Optional: set a default workspace directory
EvoSci config set default_workdir "/absolute/path/to/your/workspace"

7. Smoke test before creating services

Open two terminals:

Terminal 1 — ccproxy:

ccproxy serve --port 8000

Terminal 2 — EvoSci:

cd ~/Dev/tools/EvoScientist
EvoSci serve --auto-approve

Send a text message and a voice message to your Telegram bot. If both work, proceed to set up the background services.


8. Create launchd services (auto-start on login)

Run this script once to create both plist files:

CCPROXY=$(which ccproxy)
EVOSCI_DIR="$HOME/Dev/tools/EvoScientist"   # adjust if your path differs
EVOSCI_BIN="${EVOSCI_DIR}/.venv/bin/EvoSci"

# ── ccproxy service ──────────────────────────────────────────────────
cat > ~/Library/LaunchAgents/com.evosci.ccproxy.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key><string>com.evosci.ccproxy</string>
    <key>ProgramArguments</key>
    <array>
        <string>${CCPROXY}</string>
        <string>serve</string>
        <string>--port</string>
        <string>8000</string>
    </array>
    <key>RunAtLoad</key><true/>
    <key>KeepAlive</key><true/>
    <key>StandardOutPath</key><string>/tmp/ccproxy.log</string>
    <key>StandardErrorPath</key><string>/tmp/ccproxy.log</string>
</dict>
</plist>
EOF

# ── EvoSci serve service ─────────────────────────────────────────────
cat > ~/Library/LaunchAgents/com.evosci.serve.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key><string>com.evosci.serve</string>
    <key>ProgramArguments</key>
    <array>
        <string>${EVOSCI_BIN}</string>
        <string>serve</string>
        <string>--auto-approve</string>
    </array>
    <key>WorkingDirectory</key><string>${EVOSCI_DIR}</string>
    <key>RunAtLoad</key><true/>
    <key>KeepAlive</key><true/>
    <key>StandardOutPath</key><string>/tmp/evosci.log</string>
    <key>StandardErrorPath</key><string>/tmp/evosci.log</string>
</dict>
</plist>
EOF

# ── Load both services ───────────────────────────────────────────────
launchctl load ~/Library/LaunchAgents/com.evosci.ccproxy.plist
launchctl load ~/Library/LaunchAgents/com.evosci.serve.plist

echo "Services loaded:"
launchctl list | grep evosci

9. Check status and logs

# Are both services running?
launchctl list | grep evosci

# Live logs
tail -f /tmp/evosci.log
tail -f /tmp/ccproxy.log

Managing services

Action Command
Restart EvoSci launchctl kickstart -k gui/$(id -u)/com.evosci.serve
Restart ccproxy launchctl kickstart -k gui/$(id -u)/com.evosci.ccproxy
Stop EvoSci launchctl unload ~/Library/LaunchAgents/com.evosci.serve.plist
Stop ccproxy launchctl unload ~/Library/LaunchAgents/com.evosci.ccproxy.plist
Reload after plist edit launchctl unload <plist> && launchctl load <plist>

Troubleshooting

ccproxy not found

ccproxy is not installed. Run:

cd ~/Dev/tools/ccproxy-api && pip install -e .

ValueError: No valid OAuth access token available

ccproxy cannot find your Claude login token. Run:

ccproxy auth login claude-api

A browser window will open. Log in with your Claude subscription account. Verify the token was saved at ~/.claude/.credentials.json (hidden file, note the leading dot).

Channel telegram fatal error: python-telegram-bot not installed

The package was installed in the wrong Python environment. Use uv pip:

cd ~/Dev/tools/EvoScientist
uv pip install 'python-telegram-bot>=21.0'

zsh: no matches found: evoscientist[telegram]

Shell interprets [ as a glob. Always quote the package name:

uv pip install 'EvoScientist[telegram,stt]'   # correct
uv pip install  EvoScientist[telegram,stt]    # wrong — shell eats the brackets

Agent keeps asking to approve ffmpeg / shell commands

Add --auto-approve to the EvoSci serve command in the plist (see step 8).

Voice messages not transcribed / agent receives [voice: ...] annotation

STT is disabled or not installed:

EvoSci config set stt_enabled true
uv pip install faster-whisper

Whisper outputs gibberish (字幕by索兰娅 etc.)

This is a known Whisper hallucination on silent/very short audio. It is filtered automatically by the built-in VAD filter and no_speech_prob threshold introduced in PR #28. Make sure you are on the jhf-research branch or a release that includes that fix.

Could not find service "com.evosci.*" in domain

The plist was never loaded. Run:

launchctl load ~/Library/LaunchAgents/com.evosci.ccproxy.plist
launchctl load ~/Library/LaunchAgents/com.evosci.serve.plist

heredoc cat > file << EOF hangs in terminal

The shell variable inside the heredoc was not expanded because EOF was quoted (<< 'EOF'). Use unquoted << EOF when the content contains $VARIABLES that should be expanded, or pre-set the variables before running the command.

Services on external drive not starting at boot

/Volumes/... paths are only available after the external drive mounts. With KeepAlive: true, launchd will keep retrying every few seconds and the services will start automatically once the drive is available. This is normal behaviour for a Mac Mini where the drive is always connected.

pip install installs to conda base instead of .venv

Always use uv pip install inside the EvoScientist project directory, or explicitly target the venv:

cd ~/Dev/tools/EvoScientist
uv pip install 'some-package'

Architecture overview

Telegram app
    │  voice / text message
    ▼
python-telegram-bot (polling)
    │
    ▼
EvoScientist channel layer
    │  STT hook in _enqueue_raw()
    │  .ogg → faster-whisper → plain text
    ▼
EvoScientist agent
    │  tool calls / LLM requests
    ▼
ccproxy  (localhost:8000)
    │  OAuth token from ~/.claude/.credentials.json
    ▼
Anthropic Claude API  (claude.ai subscription)