An alternative CLI for git-bug that simplifies working with agents on issues
Files
README.md

Bug CLI Tool #

A simplified CLI interface for git-bug issue tracking. Git-bug has its own CLI, but it's not intuitive to use. This project implements an alternative API that is suitable for a user and an agent to use git-bug to collaborate on issues, while staying fully compatible with the original git-bug.

Install #

bug is installed through devenv from this repository's flake, usually via the shared devkit module (declare the bug input and import devkit in a project's devenv.yaml). The package also ships the agent skill at share/bug/skills/working-with-bug/SKILL.md; devkit copies it to ~/.agents/skills/working-with-bug/ and ~/.agents/skills/superpowers/working-with-bug/ on shell entry whenever it changes. Run devenv update bug to pick up a new version of both.

Quick Start #

Initialize git-bug in your repository:

bug init

This creates user and agent identities and configures git remotes for syncing bugs.

On a fresh checkout of a repository that already has shared bugs, bug init detects them on the origin remote, merges the existing bugs and identities, and reuses an existing identity that matches your name/email instead of creating a duplicate. On a brand-new repository it creates fresh user and agent identities.

Unlike git-bug, this sets up refspecs for remote tracking of bug references and identities, and provides a single bug sync command that keeps bugs and identities in sync with origin without needing git or jj.

Commands #

List Issues #

Display all issues in a formatted table:

bug list              # List all open issues
bug ls                # Same as above (alias)

Filtering:

bug list --filter label:bug              # Show only issues with label "bug"
bug list --filter label:bug,critical     # Show issues with both labels
bug list --filter age:<10d               # Show issues newer than 10 days
bug list --filter age:>30d               # Show issues older than 30 days

Sorting:

bug list --sort id:asc                   # Sort by ID ascending
bug list --sort id:desc                  # Sort by ID descending
bug list --sort age:asc                  # Sort by age, newest first
bug list --sort age:desc                 # Sort by age, oldest first (default)

Status:

bug list --status open                   # Show only open issues (default)
bug list --status closed                 # Show only closed issues
bug list --status all                    # Show all issues

Parent/child tree: Issues created with --parent are nested under their parent with tree markers (├─, └─). Parents sort oldest first, with each parent's children nested below it oldest first. Passing --sort forces a flat table with that sort order instead.

Overdue issues: Open issues past their due date (see --due below) get the label Overdue, shown in red. bug list adds the label when the date passes and removes it if you move the date out. To deal with an overdue issue, either close it or give it a new due date:

bug close abc1234
bug edit abc1234 --due 2026-12-15

Create a New Issue #

Using flags:

bug new --title "Bug title" --message "Detailed description"
bug new -t "Bug title" -m "Detailed description"

Interactively (opens editor):

bug new

The editor opens with a template. The first non-empty line becomes the title, and the rest becomes the description. Lines starting with ;; are ignored.

Linking to a parent issue:

bug new --title "Subtask" --message "Details" --parent abc1234
bug new -t "Subtask" -m "Details" -p abc1234

The parent ID accepts a 7-character short ID or a full ID.

Keeping sub-issues in order:

bug new -t "Step 1" -m "Details" -p abc1234
bug new -t "Step 2" -m "Details" -p abc1234 --after def5678   # def5678 = Step 1

bug ls lists issues in creation order, but creation times are recorded to the second, so issues created in the same second (common when a script or agent creates several at once) can show up in any order. --after <id> makes sure the new issue is created after the given one, waiting for the next second if needed (at most about a second). It accepts a 7-character short ID or a full ID.

Setting a due date:

bug new -t "Release notes" --due 2026-12-01                    # end of that day, local time
bug new -t "Release notes" --due 2026-12-01T17:00:00Z          # RFC3339
bug new -t "Release notes" --due "$(date --rfc-3339=seconds)"  # space instead of T also works

Read/Show an Issue #

Display an issue with all its metadata and comments:

bug read abc1234              # Display bug with ID prefix abc1234
bug show abc1234              # Same as above (alias)
bug read --repo /path abc1234 # Display bug from specific repository

Output includes:

  • Title, ID (7-char prefix), Author, Creation date, Status, Labels
  • Due (Due: <RFC3339>, only if the issue has a due date)
  • Parent (Parent: <7-char> - <title>, only if the issue has a parent)
  • Description (first comment)
  • All additional comments with their IDs

Add a Comment #

Using flags:

bug comment abc1234 --message "This is my comment"
bug comment abc1234 -m "This is my comment"

Interactively (opens editor):

bug comment abc1234

Edit an Issue or Comment #

Edit an issue:

bug edit abc1234                    # Open editor with current content
bug edit abc1234 -t "New Title"     # Update only the title
bug edit abc1234 -m "New desc"      # Update only the description
bug edit abc1234 -t "Title" -m "Desc"  # Update both
bug edit abc1234 -p def5678         # Set or change the parent issue
bug edit abc1234 --due 2026-12-15   # Set or change the due date

Changing an issue's parent gives it a new ID. git-bug stores parent links permanently, so bug edit -p re-creates the issue under the new parent, copying every comment with its original author and date. Its sub-issues are re-created too, so they stay attached. The original issue is closed with a "Superseded by " comment, which tells you which ID to use from now on. bug edit prints each old → new ID.

Parent links cannot be removed. You can't move an issue under one of its own sub-issues, because that would create a cycle. If you try to edit a superseded issue, bug tells you which issue replaced it.

Due dates work the same way. Adding a due date to an issue that has none keeps its ID. Changing an existing due date re-creates the issue (and its sub-issues) with a new ID, because git-bug stores the date permanently. Due dates cannot be removed.

Edit a comment:

bug edit def5678                    # Open editor with current comment text
bug edit def5678 -m "New text"      # Update the comment

When using the editor:

  • For issues: title on first line, blank line, then description
  • For comments: edit the comment text directly
  • Lines starting with ;; are ignored (instructions)

Open/Close Issues #

Open a closed issue:

bug open abc1234

Close an open issue:

bug close abc1234

Remove an Issue #

WARNING: This action is permanent and cannot be undone.

bug rm abc1234                    # Remove bug with short ID
bug rm abc1234567890abcdef        # Remove bug with full ID
bug remove abc1234                # Same as above (alias)

Note: Individual comments cannot be removed. Use bug rm <bug-id> to remove the entire issue including all comments.

Check Version #

Print the version of the installed bug binary:

bug version              # Prints e.g. "bug version 1.0.1"

The version is embedded at build time from the version field in flake.nix. Agents use this to determine which features are available in the installed binary.

Sync Bugs #

Exchange bugs and identities with a remote:

bug sync              # pull then push (default)
bug sync --pull       # only fetch and merge remote changes
bug sync --push       # only publish local changes
bug sync --remote upstream

This is git- and jj-independent: it uses the origin remote's URL directly. Pull merges remote changes before push, so concurrent edits are merged rather than overwritten.

IDs: Short vs Full #

Bug IDs are 64-character hex strings, but the CLI accepts shortened prefixes:

  • Short ID: First 7 characters (e.g., abc1234)
  • Full ID: Complete 64-character ID

Commands automatically resolve short IDs to full IDs. Use short IDs for convenience when interacting with bugs.

Working with a Repository in a Different Location #

All commands accept a --repo flag:

bug --repo /path/to/repo list
bug --repo /path/to/repo new --title "Title" --message "Message"

By default, commands operate on the current directory (.). The path can be any directory inside the repository; bug finds its root.

jj workspaces #

Issues live in the git repository of jj's default workspace. Run bug from any other workspace (jj workspace add), or point --repo at one, and it uses the default workspace automatically. You don't need a wrapper like bug --repo "$(jj workspace root --name default)".

Create secondary workspaces with --no-colocate:

jj workspace add --no-colocate ../myproject-feature

In a colocated repo, newer jj versions otherwise make the workspace a git worktree. That turns on git's relativeWorktrees extension, which bug's git library can't read yet, so every bug command fails until it's removed. bug prints the steps to fix it.

Agent Collaboration #

This tool supports agent collaboration. Agents use commands under bug agent which are designed for non-interactive use. See SKILL.md for agent-specific documentation. Copy the SKILL.md to ~/.agents/skills/working-with-bug. It is designed for use with superpowers skills if colocated in ~/.agents/skills/superpowers/working-with-bug.

A typical flow is to define a complicated prompt in a git-bug issue, then tell the agent to read bug [bugID] and come up with a plan. It will then use the skill in coordination with the superpowers/writing-plans and superpowers/executing-plans skills to document its plan as a comment on the bug. It will also add a summary after completion of development as a comment on the bug. I like this workflow better because it retains information about which prompts/bugs led to which plans in a way that the typical superpowers flow of a docs/plans folder full of random markdown plans does not.

Syncing Bugs #

Bugs and identities live in git refs (refs/bugs/*, refs/identities/*). Use bug sync to exchange them with the origin remote:

bug sync              # pull (fetch + merge) then push
bug sync --pull       # only fetch and merge remote changes
bug sync --push       # only publish local changes
bug sync --remote upstream

bug sync works independently of git and jj — in particular, jj git push does not move bug refs, so run bug sync to share them. Because pull runs first, concurrent edits are merged rather than overwritten.

On a fresh checkout, bug init already pulls and merges the shared bugs, so bug ls works immediately.

bug ls reminds you when you've forgotten to sync. After the table it checks origin and prints a line such as:

Out of sync with origin: 1 new bug not pushed, 2 new bugs not pulled. Run 'bug sync' to share and pick up changes.

It catches bugs and identities that exist only locally or only on the remote, and bugs whose history differs. It can miss a status change that was already fetched but not merged. The notice goes to stderr, so bug ls | grep ... is unaffected. If origin is missing or doesn't answer within 2 seconds, the check is skipped and nothing is printed.