Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pi2

English | 日本語

A Go CLI for viewing and updating your Pixela activity records in the terminal. It supports colorful contribution graphs and Retina views, adding quantities from piped input, and recording work sessions and command execution times.

Setup

Homebrew

Install from the a-know Homebrew tap:

brew install a-know/tap/pi2
pi2 config

The initial Formula builds from source and installs Go as a build dependency. On macOS, Xcode Command Line Tools (or Xcode) are required and menubar is included; Linux builds provide terminal commands only. Quit a running menu bar instance before an upgrade.

brew update
brew upgrade a-know/tap/pi2

See the Homebrew release procedure for publishing instructions.

Build from source

You need Go 1.23 or later and an existing Pixela user, USER_TOKEN, and graph. pi2 does not create users or graphs. See the Pixela getting started guide.

Build from the directory containing the source:

go mod download
go build -o pi2 .
./pi2 config
./pi2 show

To make the command available on your PATH, run go install . in the same directory. The installation directory is GOBIN, or usually $(go env GOPATH)/bin if unset. Add that directory to your PATH. The examples below assume that pi2 is on your PATH. Rebuild or reinstall after updating the source.

Configuration file

pi2 config prompts for username, graph_id, and USER_TOKEN, in that order. Token input is hidden when entered in a terminal. The file is saved to ~/.config/p2/settings.yaml. The command is named pi2, but the configuration directory is named p2.

username: your-pixela-username
graph_id: your-graph-id
USER_TOKEN: your-secret-token

The command creates any required directories and saves the file with permissions 0600. Running it again prompts for all three values and replaces the existing configuration. Leaving a field blank does not preserve its previous value. Input errors prevent saving. Do not commit configuration files containing tokens to Git.

Configuration precedence

  1. An explicit --config PATH
  2. The complete set of three environment variables below
  3. ~/.config/p2/settings.yaml
Environment variable YAML key
PIXELA_USERNAME username
PIXELA_GRAPH_ID graph_id
PIXELA_USER_TOKEN USER_TOKEN

If all three variables are unset or empty, pi2 falls back to the file. If only some are set, it reports the missing variables. Settings are not merged field by field. An explicit --config takes precedence over environment variables and produces an error if the file does not exist.

pi2 --config ./work-settings.yaml show

The config command always saves to a file; it does not change environment variables. If environment settings are active, subsequent regular commands will still prefer them. Changing the configuration directory through XDG_CONFIG_HOME is not supported.

Commands and options

pi2 [--config PATH] <command> [arguments]

Place the global option --config PATH (or --config=PATH) before the subcommand. --help, -h, and invoking pi2 without arguments print usage to standard error and currently exit with status 1. --graph and --version are not supported. Color selection is available only for prompt.

Command Arguments Behavior
config None Prompt for and save configuration
show None Display a contribution graph with month labels
retina [yyyyMMdd] Display an hourly graph; defaults to today's date on the local machine
prompt --color, --ttl, --refresh, --no-refresh, --help Display a cached, single-line hourly graph for shell prompts
menubar --foreground, --help macOS menu bar icon with a public Retina SVG popover
stats None Display statistics as formatted JSON
add One number on standard input Add to today's Pixel and display the JSON response
today None Display today's Pixel as formatted JSON
stopwatch None Start or stop Pixela's timer and display the JSON response
run -- COMMAND [ARGUMENTS...] Add command execution time in minutes

show / retina

pi2 show
pi2 retina
pi2 retina 20260922

Zero quantities appear as ; nonzero quantities, including negative values, appear as . A single space separates Pixels. Colors come from the SVG cells. Month labels appear above the graph. Retina hour labels appear at 0 (top), 6 (right), 12 (bottom), and 18 (left).

When no Retina date is supplied, pi2 uses the local machine's date. Specify the date explicitly if the graph uses a different time zone. Viewing Retina for dates other than today requires Pixela Supporter access. Retina API documentation

The layout currently treats and as one terminal column each. Labels may be misaligned if your terminal treats them as double-width characters. Widen the terminal window if the yearly graph wraps. Options for the SVG date range or mode are not supported.

stats / today

pi2 stats
pi2 today
pi2 today | jq -r '.quantity'

jq is an optional external tool. today sends returnEmpty=true, so it retrieves an empty Pixel with quantity "0" if no Pixel has been recorded today. Today API documentation

add

printf '5\n' | pi2 add
printf -- '-2.5\n' | pi2 add

Adds one number after trimming leading and trailing whitespace and newlines. Running the command again adds the quantity again. Decimal values require a float graph. Multiple input lines are not aggregated. Without piped or redirected input, the command waits for standard input to end. The implementation reads at most 1024 bytes, so use a short, ordinary integer or decimal. If today's Pixel does not exist, it is created automatically. “Today” follows the graph's time zone, or UTC if none is configured. Add API documentation

stopwatch

pi2 stopwatch  # Start
# Do your work
pi2 stopwatch  # Stop and record

Pixela manages the timer state, so pi2 does not need to keep running. Time is recorded in minutes. Measurements cannot span multiple days. For int graphs, the recorded value is rounded to an integer. Stopwatch API documentation

run

pi2 run -- go test ./...
pi2 run -- make build
pi2 run -- sh -c 'make build && make test'

Configure a graph with type=float and a unit of minutes. pi2 does not automatically change the graph's type or unit.

  • -- is required. The command and arguments that follow are executed directly.
  • To use shell syntax, explicitly invoke a shell as shown above.
  • Records elapsed wall-clock time from start to finish, not CPU time, in minutes with six decimal places.
  • Passes through the child command's standard input, standard output, and standard error. Recording diagnostics go to standard error.
  • Records time even when the child exits normally with a nonzero status, and returns that status. If the command cannot start, no time is added and pi2 exits with status 1.
  • A recording failure does not change the child's normal exit status. Requests are not retried automatically.
  • API submission time is excluded from the measurement. API requests have a 15-second timeout.
  • Time spanning multiple days is not split; it is added to the Pixel for the day handled by the add API.
  • Signal termination is handled differently from normal exit statuses. Recording is not guaranteed if pi2 is forcibly terminated or a CI job is canceled.

run measures time locally and then calls the add API. It does not change stopwatch state.

prompt / Starship integration

pi2 prompt --refresh       # Optional initial fetch; reports failures
pi2 prompt                # Display cached data; refresh asynchronously if needed
pi2 prompt --color never   # Plain text
pi2 prompt --no-refresh    # Cache-only, without starting a process

Example (each square represents one hour, from 00 through 23):

00 □□□□□□ 06 □□■■■■ 12 ■■□■■■ 18 ■■■□□□

The four labels start six-hour groups. Nonzero quantities are , zero quantities are . Cells retain their SVG colors. The output has no trailing newline; the circular retina command is unchanged. Dates use the local machine's timezone, as with retina.

Option Default Behavior
--color auto|never|16|256|truecolor auto auto uses TERM/COLORTERM even when stdout is a pipe. NO_COLOR and TERM=dumb override all palettes.
--ttl DURATION 5m Positive Go duration such as 30s or 10m; applies to successful and failed refresh attempts.
--refresh off Explicit synchronous refresh, with a 3-second request timeout. Writes no output on success; reports errors with a nonzero exit status.
--no-refresh off Never launch a background updater. Cannot be combined with --refresh.
--help off Print prompt-specific help.

Normal display never waits for a network request. An expired cache is displayed while a detached updater refreshes it; new data appears on the next prompt redraw. The first call without a cache displays nothing and starts an updater. Missing configuration, corrupt caches, network errors, or a failed process launch do not print operational errors or fail the normal display command. Invalid command-line options still report errors.

Failed updates preserve the last good same-day data and back off for the TTL. Previous-day data is not displayed. A lock prevents simultaneous requests, with recovery after one minute if an updater crashes. No permanent daemon or timer is installed: refreshes are triggered by prompt invocations. --refresh bypasses the TTL but does not duplicate an in-progress refresh.

Caches are private files (0600) under os.UserCacheDir()/pi2: typically ~/Library/Caches/pi2 on macOS, $XDG_CACHE_HOME/pi2 or ~/.cache/pi2 on Linux, and %LocalAppData%/pi2 on Windows. Cache keys separate credentials/graphs; tokens are not stored in cache contents or subprocess arguments. Cached SVG data can contain private activity data. Old cache files are not automatically pruned; remove this pi2 cache directory to clear them.

Setting up Starship

With Starship already enabled in your shell, first make sure pi2 is available on your PATH and that pi2 config or the environment variables above have been configured. Use pi2, not ./pi2, in the module command so it works outside the build directory.

Add the following to ~/.config/starship.toml (or the file selected by STARSHIP_CONFIG). If [custom.pi2] already exists, edit that section instead of adding it twice:

[custom.pi2]
description = 'Pixela hourly activity'
command = 'pi2 prompt --color auto'
when = true
format = '$output '
unsafe_no_escape = true

The default Starship format includes custom modules. If you already customize the top-level format, insert ${custom.pi2} at the desired position (or retain $custom/$all). Do not replace your existing Starship configuration. To place the graph on its own line above the usual prompt, for example, set the top-level format as follows. Place this before any [section] headers; if format already exists, edit it rather than adding another:

format = '${custom.pi2}$line_break$all'

On the first invocation, there is no cache, so the module displays nothing while fetching data in the background. Wait a few seconds, then press Enter to redraw the prompt. Completion of the fetch does not itself redraw the prompt. Subsequent invocations display the cache and trigger background refreshes when needed; you do not need to run --refresh each time.

To populate the cache before the first prompt, or diagnose a missing graph, run this manually:

pi2 prompt --refresh
pi2 prompt --color never

--refresh is optional. Do not put it in the Starship module command: it waits for the API and produces no graph output. If the graph remains absent, check that pi2 is on your PATH and use the manual refresh to see configuration/API errors. Failed background attempts back off for five minutes by default; manual refresh bypasses this interval.

unsafe_no_escape preserves per-cell ANSI colors. Use it only for this pi2 command: the renderer emits fixed labels, square glyphs and generated color sequences, never raw SVG text or API errors. Do not replace this command with untrusted/raw output while keeping the setting. For a plain-text alternative, use --color never and omit unsafe_no_escape. See Starship custom commands. This is a prompt segment, not a fixed terminal pane; it does not update during command execution.

menubar (macOS)

go build -o pi2 .
./pi2 menubar

Requires macOS 11 or later, a graphical login session, and a binary built on macOS with CGO_ENABLED=1 and Xcode Command Line Tools (or Xcode). The GUI uses the system AppKit and WebKit frameworks; no additional Go GUI library or browser installation is needed. If the compiler tools are missing, install them with xcode-select --install.

Click the small grid icon in the menu bar to open a popover showing the original Retina SVG, including its colors and hour labels. It does not reconstruct the graph from terminal output. Use Refresh to fetch again and Quit to stop the process. Clicking outside closes the popover but leaves the menu bar process running. By default, the command starts a detached background process, prints its PID, and immediately returns control to the terminal. Closing the launching terminal does not stop it. Use Quit in the popover to stop it. Login startup and a signed/notarized .app bundle are not included. Multiple launches create separate icons; quit the old instance before launching another.

For troubleshooting, keep the process attached and show diagnostics:

./pi2 menubar --foreground

In this mode, Quit or Ctrl-C stops it. Configuration and platform requirements are checked before a background process is launched. The PID message confirms process creation, not that the GUI has finished initializing; if no icon appears, use --foreground to diagnose it. Background standard input/output/error are disconnected from the terminal; no log file is created.

Only public graphs are supported: no authentication token is required or sent. The configuration precedence for this command is:

  1. An explicit pi2 --config PATH menubar file.
  2. Both PIXELA_USERNAME and PIXELA_GRAPH_ID, if either is set (partial settings are an error).
  3. ~/.config/p2/settings.yaml.

USER_TOKEN / PIXELA_USER_TOKEN are ignored by this subcommand. A token-only environment setting does not override the file. A menubar-only configuration file can contain just:

username: your-username
graph_id: your-graph-id

Alternatively, no configuration file is needed with:

PIXELA_USERNAME=your-username PIXELA_GRAPH_ID=your-graph-id pi2 menubar

Existing configuration files containing a token also work. Other subcommands and pi2 config retain their existing token requirements.

The first click starts a background request (10-second timeout). The same-day SVG is cached in memory only, separately from pi2 prompt. Opening the popover reuses it and refreshes when five minutes have elapsed since the last attempt. While open, the popover checks every 30 seconds; while closed, it does not poll the API. Refresh bypasses this interval. A failed request preserves the same-day image and displays a failure notice; a new local date clears the old image on the next check. Exiting clears the cache. The target date uses the computer's local timezone. In macOS dark mode, requests include ?appearance=dark and the SVG container uses a dark background; light mode uses the default API appearance and a white background. Appearance changes are detected when opening the popover, clicking Refresh, or at the next 30-second check while open. A change invalidates the previous appearance's cache and bypasses the five-minute interval, including after a failed request.

SVGs are embedded as images in a nonpersistent WebView with JavaScript disabled and a restrictive content policy. External resources, links, and page navigation are disabled. The original SVG's interactive links/tooltips are therefore not enabled.

On other platforms, or when built with CGO_ENABLED=0, the regular CLI remains available; menubar reports that a macOS/cgo build is required. To build a CLI-only binary on macOS:

CGO_ENABLED=0 go build -o pi2-cli .

Colors, output, and errors

The following automatic TTY rules apply to show and retina; prompt has the rules above.

Condition (first match wins) Output
Not a TTY, NO_COLOR exists, or TERM=dumb No color
COLORTERM contains truecolor or 24bit 24-bit color
TERM contains 256color Nearest 256-color palette match
Other TTYs Nearest 16-color palette match
NO_COLOR=1 pi2 show
pi2 show > graph.txt

For show and retina, pipes, files, and typical CI logs receive no color escape sequences. Colors may render incorrectly if environment variables do not reflect the terminal's actual capabilities. The appearance of 16-color output also depends on the terminal theme.

Regular API commands write results to standard output, errors to standard error, and exit with status 1 on error. For run, the exit status rules above apply. Additive and timer operations are not retried automatically. A disconnected request may already have been recorded, so check with today or another suitable command before rerunning it.

GitHub Actions

Register these Actions secrets:

  • PIXELA_USERNAME
  • PIXELA_GRAPH_ID
  • PIXELA_USER_TOKEN

The following example records test duration in pi2's own repository. Save it as a file such as .github/workflows/record-test-duration.yml. Create a float graph with a unit of minutes beforehand.

name: Record test duration

on:
  push:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7

      - uses: actions/setup-go@v7
        with:
          go-version: stable

      - name: Build pi2
        run: go build -o "$RUNNER_TEMP/pi2" .

      - name: Test and record duration
        env:
          PIXELA_USERNAME: ${{ secrets.PIXELA_USERNAME }}
          PIXELA_GRAPH_ID: ${{ secrets.PIXELA_GRAPH_ID }}
          PIXELA_USER_TOKEN: ${{ secrets.PIXELA_USER_TOKEN }}
        run: '"$RUNNER_TEMP/pi2" run -- go test ./...'

No configuration file is needed. A test failure fails the step, but a recording failure alone does not turn a successful test run into a failed step. Rerunning the workflow adds another measurement.

For another project, obtain and build pi2's source in a separate directory or provide a prebuilt binary, then replace the measured command with the project's command, such as make build. The example's go build ... . assumes that the current directory contains pi2's source.

Secrets are inherited by the child command as environment variables. Use this in jobs that execute trusted code. Secrets are normally unavailable to pull requests from forks, so this example runs on pushes and manual dispatches. See the official documentation for details on the actions and secrets:

Development and testing

go test ./...
go test -race -cover ./...
go vet ./...

Tests mock HTTP communication and do not write to real Pixela graphs. They cover commands, configuration precedence, JSON/SVG output, color fallbacks, labels, and child process input/output. The race detector requires a supported platform and an appropriate environment, including a C compiler.

When reporting a bug, include your OS, Go version, command, expected result, and actual result. For display issues, the terminal name and TERM / COLORTERM values are also useful. Do not include tokens.

Related links

About

Go CLI for Pixela activity graphs, time tracking, shell prompts, and macOS menu bar

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages