--- type: guide title: Remote Control a Pi Instance with Signal description: How to drive a self-hosted pi agent from Signal messages using signal-cli and a bridge layer. tags: - signal - remote-control - pi - automation - unverified timestamp: 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 ```mermaid 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: ```bash curl -L -O https://github.com/AsamK/signal-cli/releases/download/vVERSION/signal-cli-VERSION-Linux-native.tar.gz ``` Send a message: ```bash signal-cli -a +1234567890 send -m "Hello" +0987654321 ``` Receive messages: ```bash 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/`. ### 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-cli` daemon. Use a high-level framework to make the bridge simpler: * `signalbot` in Python. * `signal-rest-ts` in 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-api` as 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](https://github.com/AsamK/signal-cli) * [signal-cli-rest-api](https://github.com/bbernhard/signal-cli-rest-api) * [signald](https://pypi.org/project/signald/) (GitHub: — archived) * [signalbot](https://pypi.org/project/signalbot/) * [signal-rest-ts](https://www.npmjs.com/package/signal-rest-ts) (unverified) * [secured-signal-api](https://github.com/codeshelldev/secured-signal-api) ## See Also * [Pi Configuration](../pi/index.md) * [Pi Subagents](../pi/packages/pi-subagents.md) * [Agent Instruction Files](agents-files.md)