Skip to main content

bothy (Python)

Serverless, local-first sync engine that uses your own Google Drive as the transport.

⚠️ Early release. The API may still change between minor versions.

Bothy lets programs sync structured data between devices without running a server. The devices can be desktops, phones (through the Flutter package) or embedded Linux boards such as a Raspberry Pi. Each device keeps a local SQLite database and works offline; devices exchange immutable files through the user's own Google Drive or a shared folder.

Concurrent edits to different fields merge. Optionally, everything stored on Drive is end-to-end encrypted.

A typical embedded setup: a robot gets missions from a phone app and sends logs back, with no server or MQTT broker in between.

import bothy

db = bothy.Database.open("robot.db", app_id="com.example.robot",
                         remote=bothy.FolderRemote("/mnt/shared/robot"))
db.init_or_join()

missions = db.collection("missions")
missions.put("m1", {"goal": "dock", "speed": 0.5})
missions.patch("m1", {"state": "accepted"})
print(missions.get("m1"))

db.start_auto_sync()                      # or db.sync() when you choose
for change in db.changes(timeout=30):     # local and remote changes
    print(change.collection, change.id, "from another device" if change.remote else "")
db.close()

The API is synchronous and thread-safe, and calls release the GIL. Wheels are abi3, for CPython 3.9 or newer on Linux (x86_64, aarch64, armv7), macOS and Windows.

Google Drive

Bothy never signs in by itself. Use OAuth clients of your own Google Cloud project; every client of one project sees the same Drive files.

import bothy, bothy.auth

# A board without a browser: the device flow (a "TVs and Limited Input devices" client).
grant = bothy.auth.device_login("client_tv.json")   # prints a URL and a code to enter on a phone
grant.save("token.json")                            # readable only by you

tokens = bothy.auth.TokenProvider("client_tv.json", bothy.auth.Grant.load("token.json"))
db = bothy.Database.open("robot.db", app_id="com.example.robot",
                         remote=bothy.DriveRemote.folder("robot", tokens))
  • Remote type: the device flow only grants the drive.file scope, so headless devices use DriveRemote.folder (a visible Bothy/<name> folder).
  • Desktops can use bothy.auth.loopback_login with a "Desktop app" client, and DriveRemote.appdata (the hidden app folder).
  • Your own tokens: any callable (force_refresh: bool) -> str works as tokens.

Encryption

db = bothy.Database.open(..., encrypt=True, password=pw)   # the device that creates it
db = bothy.Database.open(..., password=pw)                 # devices that join
key = db.export_key()                                      # keep it to skip the password
db = bothy.Database.open(..., key=key)
  • Wrong password: raises bothy.WrongPasswordError.
  • Locked database: opened without a secret, an encrypted database is locked. Local reads and writes work; sync() raises bothy.KeyRequiredError until unlock().
  • Embedded boards: keep the key instead of the password. Unlocking with a password costs 64 MiB of memory once; syncing with the key does not. On a 4-core Cortex-A53 board, syncing two days of per-minute telemetry with the key peaked at 28 MiB of resident memory.

A complete example, a robot agent that takes missions from the Flutter demo and reports telemetry (with an optional ROS 2 bridge), is in examples/pi-agent.

Direct channels (P2P)

db = bothy.Database.open(..., p2p=True)   # stun=[] keeps it on the local network
db.start_auto_sync()
print(db.p2p_status())   # {'running': True, 'discovering': False, 'peers': [{'device_id': ..., 'state': 'connected'}]}
  • What it does: while background sync runs, devices of the same database that are online at the same time open a direct WebRTC data channel. Writes then arrive within about a second instead of at the next poll.
  • Durability: Drive stays the durable record. Segments go over the channel only after they are uploaded, and losing the channel just means waiting for the next poll.
  • Finding each other: peers find each other through small files on the remote; that usually takes 10–30 seconds after both are up.
  • Outside the local network: a STUN server (Google's public one by default) tells each device its public address. There is no relay, so a strict NAT falls back to polling.

Errors

Every engine error is a bothy.BothyError. Each error kind has its own subclass, for example OfflineError, AuthRequiredError, WrongPasswordError, KeyRequiredError and InvalidInputError.

Building from source

pip install maturin
maturin develop            # needs a Rust toolchain
python -m unittest discover -s tests

Metadata

Release files for bothy 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bothy 0.4.0
File Size Uploaded Provenance
bothy-0.4.0.tar.gz 195.6 kB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for bothy 0.4.0
File
bothy-0.4.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
bothy-0.4.0-cp39-abi3-manylinux_2_28_armv7l.whl CPython 3.9 abi3 Linux glibc 2.28+ ARMv7l Details
bothy-0.4.0-cp39-abi3-manylinux_2_28_aarch64.whl CPython 3.9 abi3 Linux glibc 2.28+ ARM64 Details
bothy-0.4.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
bothy-0.4.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl CPython 3.9 abi3 macOS 10.12+ x86-64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 11.0+ ARM64 Details

Total release size: 46.7 MB

Release files / bothy-0.4.0.tar.gz

Download URL bothy-0.4.0.tar.gz
Size 195.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8748e25273d728da6d1a49e27e99381bfa482ce0163640fed18069f82e3c62c1
BLAKE2b-256 checksum
How to use checksums
9a60ac170eb2d0a6da0237ad245b618b568a03f09654c7e277ce1b5697c222bb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / bothy-0.4.0-cp39-abi3-win_amd64.whl

Download URL bothy-0.4.0-cp39-abi3-win_amd64.whl
Size 6.9 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
867a86db1b0cbf93d519b939e400d446787384aaefb692612cefd751dfbcdf4e
BLAKE2b-256 checksum
How to use checksums
2df00a5cf56aace680f4b24c8c0a89988ae06e59a4bb43d627aa37db67225b0a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / bothy-0.4.0-cp39-abi3-manylinux_2_28_armv7l.whl

Download URL bothy-0.4.0-cp39-abi3-manylinux_2_28_armv7l.whl
Size 8.1 MB
Tags CPython 3.9 Linux glibc 2.28+ ARMv7l abi3
SHA-256 checksum
How to use checksums
a8eb4338fba5e04b0a8a697b1e29154c3d6b14820a9dc74117db6b480a485f54
BLAKE2b-256 checksum
How to use checksums
9b289d85a4c116eb50210b0d35bc3b5ff6952955864dd02860f1016b309ac538
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / bothy-0.4.0-cp39-abi3-manylinux_2_28_aarch64.whl

Download URL bothy-0.4.0-cp39-abi3-manylinux_2_28_aarch64.whl
Size 8.7 MB
Tags CPython 3.9 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
7c0f0f782e8c92d386aa8f60dfe480d5b00134048ec49327446e37ce2826854d
BLAKE2b-256 checksum
How to use checksums
9d1f28e11e69605d3a7e369a739639ed41b4c1ef0d4162dc433d6ccad0fe1e73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / bothy-0.4.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL bothy-0.4.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 8.9 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
3e18c443b2badb70debe159f462322abb79727f958803bbebc72990adefdd77d
BLAKE2b-256 checksum
How to use checksums
d5a9a1d7ff2ef2373c4fcf6cdbf105b20224950a053ef366fde08ed738aa353e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / bothy-0.4.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Download URL bothy-0.4.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Size 13.9 MB
Tags CPython 3.9 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
7dd12be5b23fabd5c3592a7210cd35994a6419325872533e28e6668b3a9c84af
BLAKE2b-256 checksum
How to use checksums
823bbf756d661971595f01ae172fa0feed07c0f13256dc750adb7e90ecd0ef1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Security for bothy 0.4.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page