-
Notifications
You must be signed in to change notification settings - Fork 0
LLM Providers
Signal supports two LLM backends. Claude is the default and the only supported provider for automated (scheduled) runs.
| Claude Code CLI | Ollama (qwen2.5:14b) |
|
|---|---|---|
| Cost | Claude Pro/Max subscription (no per-token billing) | Free (local compute) |
| Speed | ~9 sec/article, ~22 min full run | ~10 sec/article, ~28 min full run |
| Analysis quality | Significantly better — more nuanced entity extraction, sharper framing analysis | Good |
| Requires | Claude Code CLI installed + claude auth login
|
Ollama server running + model pulled |
| Safe for launchd | Yes | No — crashes macOS kernel via Metal GPU driver |
| Network | Requires internet (HTTPS to Anthropic API) | Fully offline |
| Model | Claude (version determined by CLI) | Configured in sources.yaml
|
Each LLM call in analyzer.py runs:
subprocess.run(
["claude", "-p", prompt, "--print"],
capture_output=True, text=True, timeout=180
)This spawns a new claude process per call, which makes an HTTPS request to Anthropic's API and returns the response to stdout. There is no persistent connection or session — each call is fully independent.
npm install -g @anthropic-ai/claude-code
claude --version # 2.x.x (Claude Code)Claude Code CLI uses your Claude Pro or Max subscription:
claude auth loginNo API key is required. Authentication is tied to your Anthropic account session.
echo "Say hello" | claude -p "Say hello" --printIf that returns a response, Pass 1 will work.
When Ollama is invoked from a launchd background daemon, it accesses Apple Metal for GPU inference in a non-interactive GPU session context. This mismatch triggers a Metal driver kernel panic, which hard-locks the machine. Claude avoids this entirely — it's a network call with no GPU involvement.
See Troubleshooting for the full crash investigation.
Each LLM call uses the ollama Python client:
client = ollama.Client(host=base_url)
response = client.generate(
model=model,
prompt=prompt,
options={"temperature": 0.1, "num_predict": 2048},
)This connects to the Ollama HTTP server running locally at http://localhost:11434.
# Install Ollama
brew install ollama
# Start the server
ollama serve
# Pull the model
ollama pull qwen2.5:14b
# Verify
ollama list # should show qwen2.5:14b| Model | VRAM | Speed | Quality | Use case |
|---|---|---|---|---|
qwen2.5:14b |
~9 GB | ~10 sec/call | Best | Production (manual runs) |
llama3.1:8b |
~5 GB | ~5 sec/call | Good | Development/testing |
mistral:7b |
~4 GB | ~4 sec/call | Baseline | Quick smoke tests |
# Start Ollama first
ollama serve
# Run with Ollama
SIGNAL_LLM_PROVIDER=ollama python3 main.pyDo not run Ollama via
run_and_publish.shorlaunchctl start— the Metal GPU crash will lock up your Mac regardless of available RAM.
-
SIGNAL_LLM_PROVIDERenvironment variable -
llm.providerinconfig/sources.yaml - Hard-coded fallback:
"ollama"
# Force Claude
SIGNAL_LLM_PROVIDER=claude python3 main.py
# Force Ollama
SIGNAL_LLM_PROVIDER=ollama python3 main.pyllm:
provider: claude # change to "ollama" for local inferenceThe plist already sets SIGNAL_LLM_PROVIDER=claude. To change:
<key>EnvironmentVariables</key>
<dict>
<key>SIGNAL_LLM_PROVIDER</key>
<string>claude</string> <!-- or "ollama" — but see crash warning above -->
</dict>After editing scripts/com.flexrpl.signal.plist:
launchctl unload ~/Library/LaunchAgents/com.flexrpl.signal.plist
cp scripts/com.flexrpl.signal.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.flexrpl.signal.plistThe script sets SIGNAL_LLM_PROVIDER explicitly so it behaves identically to launchd when run manually:
export SIGNAL_LLM_PROVIDER="${SIGNAL_LLM_PROVIDER:-claude}"This means claude is the default, but you can still override it:
SIGNAL_LLM_PROVIDER=ollama bash scripts/run_and_publish.shSignal · Repository · fleXRPL · Daily political intelligence — powered by local AI