# Bug CLI Tool A simplified CLI interface for [git-bug](https://github.com/git-bug/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](https://devenv.sh) 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: ```bash 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: ```bash bug list # List all open issues bug ls # Same as above (alias) ``` **Filtering:** ```bash 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:** ```bash 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:** ```bash 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: ```bash bug close abc1234 bug edit abc1234 --due 2026-12-15 ``` ### Create a New Issue **Using flags:** ```bash bug new --title "Bug title" --message "Detailed description" bug new -t "Bug title" -m "Detailed description" ``` **Interactively (opens editor):** ```bash 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:** ```bash 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:** ```bash 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 ` 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:** ```bash 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: ```bash 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: `, only if the issue has a due date) - Parent (`Parent: <7-char> - `, only if the issue has a parent) - Description (first comment) - All additional comments with their IDs ### Add a Comment **Using flags:** ```bash bug comment abc1234 --message "This is my comment" bug comment abc1234 -m "This is my comment" ``` **Interactively (opens editor):** ```bash bug comment abc1234 ``` ### Edit an Issue or Comment **Edit an issue:** ```bash 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 <new-id>" 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:** ```bash 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:** ```bash bug open abc1234 ``` **Close an open issue:** ```bash bug close abc1234 ``` ### Remove an Issue **WARNING: This action is permanent and cannot be undone.** ```bash 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: ```bash 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: ```bash 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: ```bash 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`: ```bash 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: ```bash 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.