ReplyFast
Signal messaging library for Python using Presage (Rust).
Installation
uv pip install replyfast
# With optional dependencies
uv pip install replyfast[scheduler] # For cron scheduling
uv pip install replyfast[qrcode] # For QR code display
uv pip install replyfast[all] # Everything
Contents
Quick Start
from replyfast import SignalClient
# Create client
client = SignalClient("./data")
# Link as secondary device (first time only)
def on_url(url):
print(f"Scan this QR code with Signal app: {url}")
client.link_device_sync("MyDevice", on_url)
# Send a message
client.send_message_sync("recipient-uuid", "Hello!")
# Or find contact by phone/name first
contact = client.find_contact_by_phone_sync("+1234567890")
if contact:
client.send_message_sync(contact.uuid, "Hello!")
# Receive messages
def on_message(msg):
if msg.is_queue_empty:
print("Initial sync complete")
return True
print(f"From: {msg.sender}, Body: {msg.body}")
return True # Return True to continue, False to stop
client.receive_messages_sync(on_message)
API Reference
SignalClient
| Method | Description |
|---|---|
is_registered_sync() |
Check if device is linked |
link_device_sync(name, callback) |
Link as secondary device |
send_message_sync(uuid, message) |
Send message to contact |
send_group_message_sync(group_id, message) |
Send message to group |
receive_messages_sync(callback) |
Receive messages with callback |
get_contacts_sync() |
List synced contacts |
get_groups_sync() |
List groups |
find_contact_by_phone_sync(phone) |
Find contact by phone number |
find_contacts_by_name_sync(name) |
Find contacts by name |
whoami_sync() |
Get account info |
Message
| Field | Type | Description |
|---|---|---|
sender |
str |
Sender's UUID |
body |
str | None |
Message text |
timestamp |
int |
Unix timestamp (ms) |
group_id |
str | None |
Group ID if group message |
is_read_receipt |
bool |
Is read receipt |
is_typing_indicator |
bool |
Is typing indicator |
is_queue_empty |
bool |
Initial sync complete marker |
Signal Handling
The library handles SIGINT (Ctrl+C) cleanly. When you press Ctrl+C during receive_messages_sync(), it will:
- Stop the receive loop gracefully
- Raise
KeyboardInterruptin Python - Allow cleanup code to run
try:
client.receive_messages_sync(on_message)
except KeyboardInterrupt:
pass # Clean exit
print("Stopped")
Scheduler
Send messages at scheduled times using cron syntax.
Scheduler with Message Receiving
When running a bot that both receives messages and runs scheduled tasks, start the scheduler after the initial sync is complete (indicated by is_queue_empty):
import time
from replyfast import SignalClient, Scheduler
client = SignalClient("./data")
scheduler = Scheduler()
# Define scheduled task
def periodic_task():
client.send_message_sync("recipient-uuid", "Scheduled message!")
# Register jobs before starting
scheduler.register(
"*/5 * * * *", # Every 5 minutes
periodic_task,
name="periodic-task"
)
# Message handler that starts scheduler after sync
def on_message(msg):
# Start scheduler once initial sync is complete
if msg.is_queue_empty:
print("Ready to receive messages")
scheduler.start() # Start scheduler in background
return True
if msg.body:
print(f"From: {msg.sender}: {msg.body}")
# Handle commands here
return True
# Run with reconnection loop for long-running bots
reconnect_delay = 5
while True:
try:
client.receive_messages_sync(on_message)
break # Normal exit
except KeyboardInterrupt:
break # Ctrl+C
except Exception as e:
print(f"Connection error: {e}")
print(f"Reconnecting in {reconnect_delay}s...")
time.sleep(reconnect_delay)
reconnect_delay = min(reconnect_delay * 2, 300) # Max 5 min
scheduler.stop()
print("Stopped")
Scheduler Only (No Message Receiving)
from replyfast import SignalClient, Scheduler
client = SignalClient("./data")
scheduler = Scheduler()
def send_greeting():
contact = client.find_contact_by_phone_sync("+1234567890")
if contact:
client.send_message_sync(contact.uuid, "Good morning!")
scheduler.register(
"0 9 * * *", # cron: minute hour day month weekday
send_greeting,
name="morning-greeting"
)
# Run scheduler (blocking)
scheduler.run()
# Or run in background
scheduler.start()
# ... do other things ...
scheduler.stop()
Cron Expression Format
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, 0=Sunday)
│ │ │ │ │
* * * * *
Examples:
*/5 * * * *- Every 5 minutes0 9 * * *- Every day at 9:00 AM0 9 * * 1-5- Weekdays at 9:00 AM30 */2 * * *- Every 2 hours at minute 30
Decorator Syntax
from replyfast import schedule, get_scheduler
@schedule("0 9 * * *")
def daily_task():
print("Runs every day at 9 AM")
get_scheduler().start()
Examples
The examples/ directory contains complete working examples:
example.py
Basic usage showing how to list contacts, groups, and receive messages with proper signal handling:
python examples/example.py
Demonstrates:
- Checking registration status
- Getting account info with
whoami_sync() - Listing contacts and groups
- Receiving messages with callback
- Handling typing indicators and read receipts
- Clean Ctrl+C shutdown
demo_bot.py
A bot that sends system stats on a schedule while also responding to commands:
DEMO_RECIPIENT=<uuid> python examples/demo_bot.py
Demonstrates:
- Scheduler with message receiving (starts after
is_queue_empty) - Multiple scheduled jobs (
df -hevery 5 min,free -mevery hour) - Interactive commands (ping, df, free, help)
- Reconnection loop with exponential backoff
- Proper cleanup on shutdown
Requirements
- Python 3.10+
- Rust toolchain (for building from source)
License
AGPL-3.0-or-later
Release files for replyfast 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| replyfast-0.4.0.tar.gz | 70.2 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| replyfast-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| replyfast-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| replyfast-0.4.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| replyfast-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 38.7 MB
Release files / replyfast-0.4.0.tar.gz
| Download URL | replyfast-0.4.0.tar.gz |
|---|---|
| Size | 70.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
276e6bfdbda9cf3baae39c02150b1f4150bde30c023cd8b3d7012acaf3fb9f82
|
|
BLAKE2b-256 checksum How to use checksums |
8b3cc796b74095fb50b94dab998eebe97a7635a78ac0c19e45ecc9027b1c499c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logRelease files / replyfast-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | replyfast-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 9.9 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
624ebcbfb1e45939f9aef0adf50d2f49004bd1e0ce8d3d6213db4b80c0481064
|
|
BLAKE2b-256 checksum How to use checksums |
b18db46e86026a3d65230e9d97c3d0e5254c487404962786fca38b05c29c57ba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logRelease files / replyfast-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | replyfast-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 10.5 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
1bb9fc0b0632db568c2785cbddf93626c2cc1e5efb802af0d00c683b0cb32e9c
|
|
BLAKE2b-256 checksum How to use checksums |
2e4c278b44e51ca6add39a3f383431bbde07c7d9dfe765328a42a7e0f746e561
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logRelease files / replyfast-0.4.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | replyfast-0.4.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 9.1 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
16b4049c5321e6b362e557a3a26af854bbaa4928ede1c15b215807131c8729a4
|
|
BLAKE2b-256 checksum How to use checksums |
8a7dc1d133ba40d77f950277c48ced160b56b25b64de716415c157d9bde1695f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logRelease files / replyfast-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | replyfast-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 9.1 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
4da3883663729a072425c784b65f11e44ecbae33e19b0f2c3d7ba92f27412a46
|
|
BLAKE2b-256 checksum How to use checksums |
e83aabb1ddbd6f55713a6be15d51badbee16f61c5e3203f433658a02aab7500d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency log