toot is a Mastodon client for the terminal, and its TUI has already been handed over
toot - Mastodon CLI & TUI
At a glance
- What is it?
- toot is a GPLv3 Python command line and terminal user interface client for Mastodon, covering posting, replies, media uploads, search, following, muting and blocking with simple account switching. The CLI is the maintained part, and the README is explicit that the bundled TUI is no longer being developed, with the author pointing users to a separate project for that.
- Who is it for?
- toot suits someone who lives in the terminal and wants to post, read and search on Mastodon from the command line, especially on a remote machine or over SSH where a browser is not convenient. It does not suit someone who wants a rich full screen Mastodon client, because the TUI is frozen and the recommended successor lives on a different forge, and it is the wrong tool if your workflow depends on Mastodon features the feature list does not mention.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 41 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A short feature list, honestly sized
toot is described as a CLI and TUI tool for interacting with Mastodon instances from the command line, and the feature list is short enough to read in one pass.
The first group is the posting surface: posting, replying and deleting statuses, with support for media uploads, spoiler text and sensitive content. The second is search, across statuses, accounts and hashtags. The third is the account graph, covering following, muting and blocking accounts. The fourth is simple switching between authenticated Mastodon accounts.
That last phrase is doing some work. Simple switching is not a full multi account session manager, it is a way to move between accounts you have logged in, and a user running several accounts with different personas will find that thinner than the word account management suggests.
The scope is the interesting judgement in the project. Compared with the feature surface of a browser based Mastodon client, this list is modest, and it is deliberately so. The tool is for the person who wants to read and post from a shell, and it stops there. Much of the rest of the protocol, the favourites, the lists, the filters, the media handling beyond upload, is either absent or thin, and the README does not pretend otherwise.
The audience is a Mastodon user on a Unix-like machine who is comfortable with command line tools and wants a status post to be a one line command rather than a browser tab.
Click for the commands, urwid for the screen
The dependency list is short and tells you how the tool is built.
click is the command line framework, and it is what gives the tool its --help behaviour, since the quick start starts with toot --help to show available commands and toot <command> --help for the documentation of a single command. requests handles the HTTP side, with python-dateutil for timestamps, tomlkit for the configuration file format, pysocks for proxy support, beautifulsoup4 for parsing HTML, and wcwidth for the character width calculations a terminal client needs.
The screen oriented dependency is urwid, at about version 3.0, which is the library that draws the terminal user interface. The packaging metadata confirms the split, since the package list includes toot.cli, toot.tui, toot.tui.richtext and toot.urwidgets, and the last of those is a set of urwid widgets, so the rich text rendering and the widget layer are separate modules inside the TUI.
Images are an optional extra rather than a core dependency. The images extra pulls in pillow and term-image, and the comment in the metadata says it is required to display images in the TUI. That is a sensible arrangement for a client that mostly shows text, and it means the default install is smaller.
The project also declares support for Python 3.9 and later, and both ruff and pyright are configured for that version, with a line length of 100 for ruff. A .vermin file in the repository root is the configuration for vermin, the tool that checks the minimum Python version a codebase actually requires, and that is one of the commands the test target runs.
The TUI is frozen, and its successor lives on Codeberg
The most consequential line in the README is short. Toot terminal user interface, toot tui, is no longer being developed. Instead, check out tooi, at codeberg.org/ihabunek/tooi, which the README describes as a more fully featured Mastodon TUI.
So the project has deliberately split in two. The CLI is the maintained product, and the TUI remains in the codebase as a working but frozen feature. The packaging still includes toot.tui and its subpackages, and the toot entry point is toot.cli:cli, so a user who upgrades toot still gets a TUI, they just get the last version of it rather than a moving target.
Two details in the build files confirm the status. The coverage target runs coverage html with the toot/tui/* path omitted, so the TUI is excluded from the coverage report, which is what you would do to a component you are not changing. And the README steers new users away rather than simply deprecating, which is the honest way to do it when the alternative exists.
The fact that the successor is hosted on Codeberg rather than GitHub is worth noting for anyone with a policy about where dependencies come from. The author's own projects are on both, and the migration is a deliberate statement about where the author wants the active work to live.
First run: log in, post, read
The quick start in the README is three commands, and they are the whole first session.
Log in with your account:
toot loginPost a status:
toot post "Hello, World!"And view your home timeline:
toot timelines homeThe login step is a browser based OAuth exchange, and the credentials are stored locally in the configuration file that tomlkit reads, which is what makes the account switching feature possible. Because the credentials are on disk, a shared machine needs attention, and the README's own docs site is where the details of where the file lives and how to manage it are set out.
For a first run, the order matters in a practical way. Run toot --help to see the command tree, and toot <command> --help for anything you are about to use, because the subcommand structure is where the tool's model lives. The timelines, post and search commands are the ones a new user touches first, and the media upload flags are documented per command rather than globally, so the per command help is the reference you will actually use.
The full documentation, with usage examples, is at the project's documentation site, and the installation instructions are on their own page of the same site, which is where the supported platforms and the install methods are listed.
PyPI, a zipapp and a book
The distribution story has three layers, and the third one is unusual.
The first is the standard one. The project is on PyPI as toot, built with setuptools and setuptools_scm, which means the version number comes from the repository tags rather than being written in the metadata, and the console script is declared as toot = toot.cli:cli. The build requires Python 3.9 or newer.
The second is the zipapp. The Makefile has a bundle target that assembles a directory, installs the package into it with pip, strips the dist-info and the pycache directories, and then runs python -m zipapp with the interpreter set to /usr/bin/env python3 and compression enabled, producing a file named toot-`git describe`.pyz. The result is a single executable archive that runs anywhere a Python 3 interpreter exists, with no installation and no virtual environment, which is a genuinely useful shape for a tool you want to copy to a server.
The third is the documentation build. There is a book.toml and a book.css at the repository root, which are mdBook files, so the documentation site is built with mdbook build, served locally with mdbook serve on port 8000, and deployed with rsync to a web host. The changelog is generated rather than written, since the changelog target runs a script that produces CHANGELOG.md and copies it into the docs directory, with the structured source living in changelog.yaml.
For a user none of that matters except the last point, which is that the documentation and the changelog are part of the repository and built from it, so they are as current as the code.
One test command, three tools, and the TUI left out
The test target is a good summary of how the project is run:
pytest -v
flake8
vermin tootwhich runs pytest -v, then flake8, then vermin toot. Three tools with three jobs. Pytest runs the suite, flake8 checks the style, and vermin works out the minimum Python version the code actually needs, which is what keeps the stated 3.9 requirement honest rather than aspirational. The development dependencies back this up, with pytest, pytest-xdist for parallel runs, mypy and pyright for typing, flake8 and vermin for linting and version checking, and pudb for debugging.
The coverage target is worth a second look. It runs coverage erase, coverage run, coverage html with the toot/tui/* path omitted, and then coverage report. The omission is the TUI, which is the same signal as the README statement: the component is still shipped but is not being measured or changed.
The rest of the Makefile is release and housekeeping machinery. dist runs python -m build, publish runs twine upload over the built artefacts, clean removes the build directories and the pyz bundle, and docs-deploy syncs the built book to the web host with rsync using the --delete flag, which is a small thing that tells you the deployment target is a directory that mirrors the book exactly.
The project also carries the usual small files that a maintained Python repository has: pytest.ini, a.coveragerc, MANIFEST.in for the source distribution, and a CHANGELOG.md.
Where toot stops, and how it is maintained
The limits are clear from the shape of the project. It is a client, not a server, and it covers the common actions rather than the protocol. There is no scheduled posting, no account lists, no filter management, no timeline moderation, and the TUI has stopped moving. A user whose Mastodon workflow depends on those things needs a full client.
The account switching is described as simple, and for a handful of personal accounts that is exactly what you want. For someone running many accounts from a shared machine, the local credential file becomes the thing to think about.
The support model is worth noting because it is entirely community based. Discussion, support and patches go through a mailing list at lists.sr.ht, there is an informal IRC channel, #toot, on libera.chat, and issues are tracked on GitHub. The project also has a documentation site, toot.bezdomni.net, with its own installation page, usage page and changelog page, and the author's own mastodon.social account is linked from the README.
On maintenance, the release history shows 0.52.1 and 0.52.0 both on 2026-04-04, and 0.51.1 in February 2026, and the last push was on 2026-09-12, so the repository is not archived and work is landing on master between releases. The licence is GPLv3, with the metadata declaring it as GPL-3.0-only, so a fork that is distributed has to carry the same terms, and the copyright is held by Ivan Habunek and contributors.
The honest summary is that toot is a small, well packaged command line client that has made a deliberate choice about where its future lies, and the parts it has stopped maintaining are still there, still working, and clearly marked.
Editorial conclusion
toot suits someone who lives in the terminal and wants to post, read and search on Mastodon from the command line, especially on a remote machine or over SSH where a browser is not convenient. It does not suit someone who wants a rich full screen Mastodon client, because the TUI is frozen and the recommended successor lives on a different forge, and it is the wrong tool if your workflow depends on Mastodon features the feature list does not mention. Verify first that the version you install still has the commands you expect, since the CLI surface and the TUI have drifted apart, and read the CHANGELOG.md, which is generated from changelog.yaml, before upgrading.
Frequently asked questions
What is toot?
It is a CLI and TUI tool for interacting with Mastodon instances from the command line, covering posting, replying and deleting statuses, media uploads, spoiler text and sensitive content, search across statuses, accounts and hashtags, following, muting and blocking, and switching between authenticated accounts.
Is the toot terminal user interface still maintained?
No. The README states that toot tui is no longer being developed and points to tooi, a more fully featured Mastodon TUI hosted on Codeberg. The TUI code remains in the package, and the coverage target omits the toot/tui path.
How do I log in and post with toot?
Run toot login to authenticate your account, then toot post "Hello, World!" to publish a status, and toot timelines home to read your home timeline. The quick start also points at toot --help and toot <command> --help for the command list and per command documentation.
Does toot need any extra packages for images?
Only if you want to display images in the TUI. The project defines an images optional dependency that pulls in pillow and term-image, and the metadata notes it is required to display images in the terminal user interface.
What licence is toot released under?
GPLv3, declared as GPL-3.0-only in the package metadata, with the copyright held by Ivan Habunek and contributors.
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/ihabunek-toot)Was this useful?