Guide

Scripting

octoscope isn't only a TUI. Two flags fetch once, print, and exit — for quick checks, shell status-lines, cron jobs and pipelines.

--plain — a text summary

A static, human-readable digest of the same data the dashboard shows, printed to stdout. No alt-screen, no colour codes to fight with.

$ octoscope --plain
$ octoscope torvalds --plain     # anyone's public profile

--json — a stable contract

The same data as JSON, versioned (schema_version) and documented — so a script can depend on its shape. Fields are added additively, every list is always an array, and a breaking change bumps the version.

$ octoscope --json | jq '.social.total_stars'
$ octoscope --json --public-only > snapshot.json

Both honour --public-only and the usual auth cascade, and the two are mutually exclusive.

--activity — the feed, on request

The recent-activity feed — the same events the TUI's Activity tab shows — is opt-in in both output modes. It costs one extra API request, and most scripted runs only want the counters, so it is off unless asked for.

$ octoscope --json --activity | jq '.recent_activity[0]'
$ octoscope --plain --activity

Two details worth knowing. recent_activity is the one list that is absent rather than empty when there is nothing to report: no key means the flag was not passed, [] means it was and the account has no recent events. And the rows are newest first because octoscope sorts them — GitHub's own feed interleaves two id spaces and arrives roughly a quarter out of order.

On its own, --activity is a usage error rather than a no-op: the TUI shows that tab regardless, so there is nothing for the flag to do without --plain or --json.

↗

The full field-by-field JSON schema lives in the README's Scripting section — this page is the tour, the README is the contract.

Two things about the shape that a field list will not warn you about. Counts are separate from lists, because the lists are capped — sponsors holds up to 20 entries while sponsors_total is what GitHub reports, so comparing len(sponsors) against “how many sponsors do I have” is wrong on a busy account. Same for repositories, PRs and issues, which have caps of their own. And monthly_sponsors_income_cents is only ever present for the account the token belongs to — GitHub answers that field with 0 for anybody else, so it is omitted rather than emitted as a zero somebody could read as a measurement.

The notification inbox is deliberately not in either output. It is loaded on demand in the TUI rather than on every refresh, so putting it here would mean a REST call on every --json run for a field most callers do not want. Tracked as issue #185 — this paragraph cited #125 until 0.35.0, which is a different gap, the activity feed, and one that --activity now closes.

In a container

Since v0.31.0 the same two flags are available as an image, which is the shape a CI step wants — no install, fetch once, print, exit:

$ docker run --rm -e GITHUB_TOKEN ghcr.io/gfazioli/octoscope:latest --json | jq .social

-e GITHUB_TOKEN with no value passes the variable through from the surrounding environment rather than putting the token on the command line, where it would show up in ps and in shell history.

Two behaviours worth knowing before you depend on it. With no token it exits 1 and writes nothing to standard output — but a shell pipeline only notices that with set -o pipefail, since otherwise the exit status is jq's and jq is perfectly happy with no input. GitHub Actions does not enable it for you unless the step says shell: bash. And with no flag at all the container refuses rather than hanging, because the dashboard needs a terminal it does not have.