CLI tool
bellingcat/octosuite avatar
bellingcat/octosuite

octosuite: GitHub data from the terminal

Terminal-based toolkit for GitHub data analysis.

1,896 stars159 forksPythonMIT

At a glance

What is it?
octosuite is a Bellingcat terminal toolkit that exposes GitHub users, repositories, organisations and search through one CLI, one Python API and one interactive TUI. The README documents terminal, command line, and Python library interfaces for GitHub data analysis.
Who is it for?
Use octosuite when you want a quick read on a public GitHub account, repository or organisation from a shell, and when writing a small script that only needs the four documented object types. Do not build a pipeline on it if you need authenticated rate limits, because the README documents no token argument on any command.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 45 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Four objects, three front ends, one endpoint

The shape of octosuite is easy to summarise: it wraps four GitHub object types and exposes each through three front ends over the same code.

The four objects are `User`, `Repo`, `Org` and `Search`. For each one there is a command line form, a Python class, and data type flags to choose which collection to pull. For a user the README lists profile, repos, subscriptions, starred, followers, following, orgs, gists, events and received_events. For a repository it lists profile, forks, issue_events, events, assignees, branches, tags, languages, stargazers, subscribers, commits, comments, issues, releases, deployments and labels. For an organisation: profile, repos, events, hooks, issues and members. For search: repos, users, commits, issues and topics.

The three front ends share that surface. There is a terminal interface you launch with `octosuite -t/--tui` and navigate with arrow keys and Enter. There is the command line, where each command takes an entity and a data type flag. And there is the library, where you import the same four classes.

This is a convenience tool, and Bellingcat states its purpose as terminal based GitHub data analysis for OSINT work. The design assumption is that you know what you want before you start: a subject account, a repository, an organisation, or a search phrase.

One structural note from the packaging. `pyproject.toml` sets `version = "5.1.0"` directly in the project table, and the entry point is `octosuite = "octosuite.app.main:start_app"`. The source lives under `src/` and the lock file is `uv.lock`, so the project is built around uv rather than a pip-tools or poetry workflow.

Pagination is explicit everywhere, and capped at 100

Every listing call in this tool is paginated, and the flags are consistent across the command line and the library.

On the CLI the common options are `--page` for the page number, defaulting to 1; `--per-page` for results per page with a maximum of 100 and a default of 100; `--json` for JSON output; and `--export DIR` to write to a directory. The README tells you to run `octosuite <command> --help` for the data type flags specific to each command.

The Python API mirrors this exactly. A `User` object takes page and per_page keyword arguments, and so do `repos`, `followers` and the rest:

python
from octosuite import User, Repo, Org, Search

user = User("torvalds")
exists, profile = user.exists()
if exists:
    repos = user.repos(page=1, per_page=100)
    followers = user.followers(page=1, per_page=50)

repo = Repo(name="linux", owner="torvalds")
exists, profile = repo.exists()
if exists:
    commits = repo.commits(page=1, per_page=100)
    languages = repo.languages()

The `exists()` convention is worth noting. Every one of the four classes returns a two element tuple of a boolean and the payload, so a missing account or repository is a normal return value rather than an exception. Whether a not found user and a transport failure are distinguishable is not stated in the README.

The hard cap of 100 per page is the constraint to plan around. Pulling a large event history means looping, and the library does not document a helper that does that for you.

Installation and the Python floor of 3.13

Installation from PyPI is one command:

bash
pip install octosuite

The interesting detail is the interpreter requirement. `pyproject.toml` sets `requires-python = ">=3.13"`, and the repository carries a `.python-version` file at the top level.

Runtime dependencies are few and all user interface or terminal related: `rich>=14.3.3` for terminal rendering, `questionary>=2.1.1` for the interactive prompts in the TUI, `pyfiglet>=1.0.4` for the banner, and `update-checker>=0.18.0` to tell you about new versions. The presence of `update-checker` means the tool phones home for version information on its own, which is worth knowing if your analysis runs in an isolated environment.

The development workflow is uv based. The Makefile targets are `install` for `uv pip install.`, `dev` for `uv pip install.[dev]`, `run` which installs and then runs `uv run octosuite`, `format` for `uv run black.`, `sync` for `uv sync`, `lock` for `uv lock`, and `update` for `uv lock --upgrade` followed by `uv sync`. The dev extra pulls in `black>=26.1.0`.

A first run against a public account looks like this:

bash
octosuite user torvalds
octosuite user torvalds --repos --page 1 --per-page 50
octosuite user torvalds --followers --json

The equivalent library call is three lines:

python
from octosuite import User

user = User(name="torvalds")
exists, profile = user.exists()

if exists:
    from pprint import pprint
    pprint(profile)

Exports are available in JSON, CSV and HTML, which is what makes this useful beyond a terminal glance: you can dump a collection once and analyse it with something else.

No token argument anywhere, and that bounds what it can do

The most consequential gap in the documentation is authentication.

Not one of the README examples passes a token, and the common options list is limited to page, per page, json and export. The README does not document how to raise the GitHub rate limit, how to read a private repository, or how to authenticate at all. There is a `[project.urls]` entry pointing at Issues and the Repository, but no mention of a token flag, an environment variable or a config file.

That has direct consequences for the Bellingcat OSINT use case this tool is built for. A subject with a few thousand public events is a few dozen pages at 100 per page, and unauthenticated GitHub API access has a low hourly ceiling. Whether the underlying HTTP client sends a token from some other source, such as an environment variable the README omits, is not stated in what is available here, so treat it as unauthenticated until you verify otherwise in the source.

The flip side is that a tool with no credentials is pleasant to hand to someone else. There is nothing to configure and nothing to leak, which is a reasonable trade for short investigative queries and a poor one for bulk collection.

The second limitation is the release cadence. Three releases appear in quick succession: 4.0.0rc0 on 2026-01-06, then 5.0.0 and 5.1.0 both on 2026-02-28. A major version bump with a release candidate and the stable landing in the same week suggests API churn between majors, so pin the version if you script against it. The repository is not archived and the last push was on 2026-09-08, and the package classifies itself as `Development Status :: 5 - Production/Stable`.

Where octosuite fits against the gh CLI and the REST API

The obvious comparison is GitHub's own `gh` command line tool, and the difference is scope rather than quality.

octosuite is scoped the other way. It reads public data about accounts, repositories and organisations you may have no relationship with, which is the investigation case. That is a real gap `gh` does not try to fill.

Against direct use of the REST API with `requests`, octosuite saves you the four pieces of boilerplate: endpoint construction per object type, the pagination loop, the JSON assembly, and the data type routing the CLI handles with flags. What it adds is a dependency on a wrapper whose behaviour on a 5.x minor release may differ from 4.x, plus the terminal stack of `rich`, `questionary` and `pyfiglet` even when you only want the library.

For anything you run repeatedly or at scale, the REST API with your own token and your own retry and backoff logic remains the more controllable option.

Editorial conclusion

Use octosuite when you want a quick read on a public GitHub account, repository or organisation from a shell, and when writing a small script that only needs the four documented object types. Do not build a pipeline on it if you need authenticated rate limits, because the README documents no token argument on any command. Check first that your Python is 3.13 or newer, since requires-python is set to >=3.13, and expect to pin version 5.1.0 because a 4.0.0 to 5.0.0 major bump landed within the same release window as 4.0.0rc0.

Frequently asked questions

How do I install octosuite?

Run pip install octosuite from PyPI. The package requires Python 3.13 or newer because pyproject.toml sets requires-python to >=3.13, and the repository ships a .python-version file.

Can octosuite read private repositories or raise the GitHub rate limit with a token?

The README documents no token argument on any command or constructor, and the listed common options are only page, per page, json and export. No authentication method is described, so plan for public data and low rate limits.

What data types can octosuite pull from GitHub?

For users: profile, repos, subscriptions, starred, followers, following, orgs, gists, events and received_events. For repositories: profile, forks, issue events, events, assignees, branches, tags, languages, stargazers, subscribers, commits, comments, issues, releases, deployments and labels. Organisations add hooks and members, and search covers repos, users, commits, issues and topics.

How do I use octosuite as a Python library?

Import User, Repo, Org and Search from octosuite, call exists() on the object to get a boolean and the payload, then call the collection methods with page and per_page arguments. The README notes per_page is capped at 100.

What licence is octosuite released under and who maintains it?

MIT, with a LICENSE file at the repository root, authored by Ritchie Mwewa of Bellingcat. The package home is listed as bellingcat.com and the version in pyproject.toml is 5.1.0.

Official sources

  1. bellingcat/octosuite on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bellingcat-octosuite.svg)](https://hysenlabs.com/projects/bellingcat-octosuite)

Was this useful?