PyBitmessage: an emergency release, a stricter fix, and seven hours between them
Reference client for Bitmessage: a P2P encrypted decentralised communication protocol:
At a glance
- What is it?
- A reference client for a decentralised encrypted messaging protocol whose newest releases are an emergency fix for an exploitable bug and a follow-up tightening, both published on the same evening in 2018, whose install command writes icons into the source tree, whose extras include one whose name is a platform marker, and whose container installs a dependency by hand because the base install declares only one.
- Who is it for?
- PyBitmessage is worth reading if you are studying how a decentralised messaging protocol is put together, and worth installing only if you accept an eight-year-old release line. Take it when you want the reference implementation rather than a maintained product, and read the protocol specification alongside the code, since the documentation the project points at is pinned to the version its default branch is named after.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 129 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 5, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two releases on one evening, and no release since
The release list is short and the gap is long. v0.6.2 is dated March 2017. Then two releases land on the same day, February 2018: v0.6.3, titled as an emergency release to fix an exploitable bug, published at 16:36, and 0.6.3.2, titled as stricter exploit mitigation, published at 23:27 the same evening. So a security fix was followed within seven hours by a second one on top of it. The numbering also changes shape between them, from a three-part version with a v prefix to a four-part version without one, and the release after that in the list goes back to the three-part form. The repository's default branch is named v0.6, matching the documentation the project links, which is itself a readthedocs build pinned to the v0.6 specification. The last commit on that branch is dated 2026-05-29, so the working tree has moved a long way from anything released.
Installing writes icon files back into the checkout
The packaging script subclasses the standard install command and, before delegating to it, prepares icon directories inside the tree. It creates a scalable icons directory and copies one source file into it under the package's own name, then creates a 24 by 24 directory and copies a second file there. So a plain install leaves new files under the desktop directory of your checkout. The path handling is inconsistent inside the same script: the readme and the requirements file are opened through a path computed from the script's own location, while the two icon copies use bare relative paths, which means they resolve against whatever directory you ran the command from. Run the build from the project root and it works; run it from anywhere else and the parts that use the computed path still work while the icon preparation does not.
pip2 install jsonrpclib .One extra is named after a platform marker
The optional dependency table has eleven entries, and ten of them are ordinary names: documentation, a GObject introspection binding, a JSON remote procedure library, desktop notifications, an OpenCL pair, a thread naming library, QR code generation, a Tor controller library, an XDG path library and a hardened XML parser. The eleventh is not a name. Its key is the library plus a semicolon and a platform condition limiting it to Windows, with a single sound module inside it. An extra whose key carries an environment marker is not something you can select by typing its short name, because the short name and the key are not the same string. It is the kind of thing that works by accident in one installer and not in another, and it is the only entry in the table where the condition and the name are fused together.
The declared install requirement is one package
The packaging script declares a single install requirement, a compatibility shim library, and that is the whole hard list. Everything else the program needs lives in a separate requirements file: a coverage tool, a process utility, a cryptographic library, a Qt binding behind a version and architecture marker, a mocking library behind a Python 2 marker, a thread naming library on Linux, the shim again, and a virtual framebuffer wrapper on Linux with a version ceiling below 0.2.10. So a plain install pulls one package and leaves the rest to you, which is why the container image installs the JSON remote procedure library by hand on the line above: it is an optional extra, and the image wants it. Separately, the build compiles a C extension from a source file under the src directory against the threading and crypto system libraries, so a compiler and two development headers are part of installing this at all.
The container bakes a config and deletes everything else
The image starts from the bionic base, which is Ubuntu 18.04, and installs build tools plus the development headers for capabilities and OpenSSL. Two ports are exposed, 8444 and 8442. The whole build context is added into a home directory that is also declared as the working directory and as the value of an environment variable the client reads. After installing, the image removes the apt caches and then removes that home directory entirely. It then creates a system user and applies ownership to the same path, which no longer exists at that point, before switching to that user. The last build step runs the client in its test mode to generate a default configuration, then deletes the four files that run produced: the known nodes database, the message database, the debug log and the singleton lock. The result is an image that ships a generated config and no peers.
pybitmessage -tThe entry point is a launcher script copied in from the packages directory, and the default command is daemon mode.
A Python 2 marker and a capped framebuffer wrapper
Three lines of the requirements file describe a codebase that still spans two language generations. The build script's shebang names Python 2.7, and the requirements file carries a mocking library conditioned on Python 2.7 or older, which by definition installs nothing on any modern interpreter. The container reinforces this by installing with pip2. Then there is the framebuffer wrapper, pinned below version 0.2.10, which is the only dependency in the file with an upper bound rather than a floor, and it will conflict with anything else in your environment that wants a newer one. The Qt binding is conditioned on both a Python floor and an x86_64 machine, so on Apple silicon the graphical dependency is skipped silently and the client runs without a desktop interface.
Two source directories and two test suites
The tree holds a package directory and a src directory side by side, and they do different jobs. The version the packaging script reports is imported from a module inside src, and the C extension source that gets compiled also lives under src, while the importable package itself is the directory named after the project. That split is easy to misread when you are looking for the version number or trying to patch the extension. Testing is duplicated the same way. There is a plain test module and a separate one for the Kivy interface, a shell script that runs the Kivy tests inside a container, another that tests the container image itself, and a separate requirements file for the Kivy extras. Around those sit a Debian packaging file, a man page directory, a tox configuration, a buildbot directory and a dev container definition.
The protocol claims, and a contribution gate in two sentences
The readme is short and makes four claims about the protocol. It is decentralised and trustless, so you need not inherently trust entities such as root certificate authorities. It uses strong authentication, so the sender of a message cannot be spoofed. It aims to hide metadata from passive eavesdroppers. And from those, the sender and receiver of messages stay anonymous. The development section is two sentences and the second one is a gate: pull requests are welcome, but if you plan a non-trivial amount of work on new features you should describe your ideas in an issue first. The page also carries a live channel address inline, in the long identifier form the protocol uses for channels, which means joining the project's own chat is a copy and paste away. The references point at a wiki installation page rather than the installation file in this tree.
Editorial conclusion
PyBitmessage is worth reading if you are studying how a decentralised messaging protocol is put together, and worth installing only if you accept an eight-year-old release line. Take it when you want the reference implementation rather than a maintained product, and read the protocol specification alongside the code, since the documentation the project points at is pinned to the version its default branch is named after. Build from source rather than trusting a packaged install, because the build compiles a C extension against two system libraries and the base dependency list is a single package. Expect to add optional pieces yourself, since the container image has to install one of them by hand. And check which of the two licence files in the tree applies before you redistribute anything.
Frequently asked questions
What is bitmessage?
A peer-to-peer communication protocol for sending encrypted messages to one person or to many subscribers. The readme describes it as decentralised and trustless, so you need not inherently trust entities such as root certificate authorities, using strong authentication so a sender cannot be spoofed, and aiming to hide metadata from passive eavesdroppers.
How do I install PyBitmessage?
The readme points at a wiki page on compiling instructions rather than repeating them, and the repository also carries an installation file of its own. Installing from source compiles a C extension against the threading and crypto system libraries, and the packaging script declares only one hard dependency, so the rest come from the requirements file.
What is the newest PyBitmessage release?
Two releases from February 2018: v0.6.3, an emergency release to fix an exploitable bug, and 0.6.3.2, stricter exploit mitigation, published the same evening. Before them was v0.6.2 in March 2017. The default branch is named v0.6 and its last commit is dated 2026-05-29.
What license does PyBitmessage use?
The repository metadata carries no license value at all, and the tree contains two files named COPYING and LICENSE. The applicable terms are in those files rather than in the metadata, so check which one the project treats as authoritative.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bitmessage-pybitmessage)