Copy of the legacy ~/.pi/agent/docs tree rebuilt as the command-center knowledge base: concept files promoted to path identity, index listings stripped of frontmatter, all wikilinks/relative links resolved, every checkable claim verified against the live fleet (Dankserver = Ryzen 7 7700X + RTX 3090; Strix Halo is Dankclaw), unverifiable claims tagged. kb-lint exits 0.
4.1 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | |||||
|---|---|---|---|---|---|---|---|---|---|
| guide | Remote Control a Pi Instance with Signal | How to drive a self-hosted pi agent from Signal messages using signal-cli and a bridge layer. |
|
2026-08-11 |
verified: 2026-08-28
Remote Control a Pi Instance with Signal
This page explains how to send a command to a self-hosted pi agent from a Signal message. Signal has no official bot API, so you must use an open-source bridge. The bridge delivers a Signal message to the agent and then returns the agent reply over Signal.
Overview
flowchart LR
U[Signal client] -->|Signal message| B[signal-cli-rest-api]
B -->|WebSocket or REST| G[bridge layer]
G -->|stdin or webhook| P[pi agent]
P -->|reply| G
G -->|send| B
B -->|Signal message| U
Signal Bridges
Signal provides no public bot platform. Use one of these open-source bridges.
signal-cli
signal-cli is a Java command-line client. It runs in CLI, daemon, or JSON-RPC mode. Use it to register a number, link a device, send, and receive.
Install the GraalVM native build to avoid JVM startup time:
curl -L -O https://github.com/AsamK/signal-cli/releases/download/vVERSION/signal-cli-VERSION-Linux-native.tar.gz
Send a message:
signal-cli -a +1234567890 send -m "Hello" +0987654321
Receive messages:
signal-cli -a +1234567890 daemon --http=localhost:3000
The daemon exposes POST /api/v1/rpc and GET /api/v1/events.
Keep signal-cli updated. A release older than three months can break against the Signal server.
signal-cli-rest-api
signal-cli-rest-api wraps signal-cli in a Docker container. It exposes REST endpoints and a WebSocket receive channel. This is the easiest bridge to deploy.
Run it with MODE=json-rpc for a single daemon with WebSocket receive. Send a message with POST /v2/send. Receive messages from GET /v1/receive/<number>.
signald
signald is a lighter Rust alternative. It runs as a daemon and communicates over WebSocket. It uses fewer resources than the Java-based signal-cli.
Bridge the Message to the Agent
Use one of these patterns to connect the Signal bridge to the pi agent.
- Webhook: the bridge posts the incoming message to the agent over HTTP.
- WebSocket: a script subscribes to incoming messages and calls the agent.
- File polling: a script writes each message to a file that the agent watches.
- JSON-RPC pipe: the agent runs as a child process of the
signal-clidaemon.
Use a high-level framework to make the bridge simpler:
signalbotin Python.signal-rest-tsin TypeScript.
Account Setup
Use a dedicated number for the bot. Register the number as its own account, or link it to your phone as a linked device.
A primary account allows up to five linked devices. Use a dedicated secondary SIM or a landline for a self-contained bot.
Registration requires a captcha from the Signal captcha site. Verify with an SMS code. Use voice verification for landlines.
Security and Gotchas
Protect the bot keys. The bridge stores cryptographic keys in its data directory. Anyone with access to that directory can impersonate the bot.
- Restrict the bridge to localhost.
- Use API tokens and IP filtering if you expose it.
- Use
secured-signal-apias an authenticated gateway for internet access.
The Signal protocol expects regular receive calls. Use daemon mode or an auto-receive schedule to keep messages in sync. Do not combine REST receive and auto-receive, or you will get duplicate messages.
Citations
- signal-cli
- signal-cli-rest-api
- signald (GitHub: https://github.com/signald/signald — archived)
- signalbot
- signal-rest-ts (unverified)
- secured-signal-api