The gh-attach CLI provides a command-line interface for uploading images to GitHub issues, PRs, and comments. It works both as a standalone tool and as a gh CLI extension.
The system SHALL provide a CLI executable named gh-attach.
- GIVEN the package is installed globally via
npm install -g gh-attach - WHEN the user runs
gh-attach --version - THEN it SHALL print the version number and exit with code 0
- GIVEN the tool is installed via
gh extension install - WHEN the user runs
gh attach --version - THEN it SHALL behave identically to standalone mode
- GIVEN no subcommand is provided
- WHEN the user runs
gh-attach - THEN it SHALL display the help text and exit with code 0
The system SHALL provide an upload command as the primary action.
- GIVEN a valid session and a file path
- WHEN the user runs
gh-attach upload ./screenshot.png --target owner/repo#42 - THEN it SHALL upload the image and print the markdown embed to stdout
- AND exit with code 0
- GIVEN the user specifies a strategy
- WHEN the user runs
gh-attach upload ./img.png --target #42 --strategy release-asset - THEN it SHALL use only the specified strategy
- GIVEN the user is in a git repo with a GitHub remote
- WHEN the user runs
gh-attach upload ./img.png --target #42 - THEN it SHALL infer the owner/repo from the git remote
- GIVEN the
--format urlflag - WHEN the upload completes
- THEN it SHALL print only the raw URL (no markdown wrapping)
- GIVEN no
--formatflag or--format markdown - WHEN the upload completes
- THEN it SHALL print
to stdout
- GIVEN the
--format jsonflag - WHEN the upload completes
- THEN it SHALL print
{ "url": "...", "markdown": "...", "strategy": "..." }to stdout
- GIVEN multiple file paths
- WHEN the user runs
gh-attach upload ./a.png ./b.png --target #42 - THEN it SHALL upload each file sequentially
- AND print each result on a separate line
- GIVEN image data piped via stdin
- WHEN the user runs
cat screenshot.png | gh-attach upload --target #42 --stdin --filename screenshot.png - THEN it SHALL read the image from stdin and upload it
- GIVEN an upload that fails
- WHEN the error occurs
- THEN it SHALL print the error message to stderr
- AND exit with a non-zero exit code (1 for general errors, 2 for auth errors)
The system SHALL provide a login command for interactive authentication.
- GIVEN no existing session
- WHEN the user runs
gh-attach login - THEN it SHALL open a browser window to GitHub
- AND wait for the user to authenticate
- AND save the session cookies to the configured state file
- AND print a success message
- GIVEN the
--state-pathflag - WHEN the user runs
gh-attach login --state-path ~/.gh-attach/session.json - THEN it SHALL save the session to the specified path
- GIVEN an existing session
- WHEN the user runs
gh-attach login --status - THEN it SHALL check if the session is still valid
- AND print the status (valid/expired) and the authenticated username
The system SHALL provide a config command for managing settings.
- GIVEN an existing config
- WHEN the user runs
gh-attach config(no action argument) - THEN it SHALL print all configuration key-value pairs
- AND behave identically to
gh-attach config list
- GIVEN an existing config
- WHEN the user runs
gh-attach config list - THEN it SHALL print all configuration key-value pairs
- WHEN the user runs
gh-attach config set strategy-order "release-asset,browser-session" - THEN it SHALL update the strategy preference order
- WHEN the user runs
gh-attach config set default-target owner/repo - THEN it SHALL set the default target repository for uploads
- GIVEN the config file
- THEN it SHALL be stored at
~/.config/gh-attach/config.json(XDG compliant) - AND be overridable via
GH_ATTACH_CONFIGenvironment variable
The system SHALL support standard global options.
- GIVEN the
--verboseor-vflag - WHEN any command is run
- THEN it SHALL print debug information to stderr (strategy selection, HTTP requests, timing)
- GIVEN the
--quietor-qflag - WHEN any command is run
- THEN it SHALL suppress all output except the final result or errors
- GIVEN the
--no-colorflag orNO_COLORenvironment variable - WHEN any command produces output
- THEN it SHALL omit ANSI color codes
- GIVEN
--helpor-hon any command - WHEN the user invokes it
- THEN it SHALL print command-specific help and exit with code 0
The system SHALL use structured exit codes.
- GIVEN any CLI execution
- THEN exit code 0 SHALL indicate success
- AND exit code 1 SHALL indicate a general error
- AND exit code 2 SHALL indicate an authentication error
- AND exit code 3 SHALL indicate a validation error (bad input)
- AND exit code 4 SHALL indicate a network/upload error
The system SHALL be distributable as a gh CLI extension.
- GIVEN the repository
- THEN it SHALL include a
gh-extensionbinary entry point - AND the repository name SHALL be
gh-attach(matchingghextension convention)
- GIVEN the user runs
gh extension install owner/gh-attach - THEN the tool SHALL be usable as
gh attach upload ...
The system SHALL support configuration via environment variables.
- GIVEN
GITHUB_TOKENorGH_TOKENenvironment variable - WHEN the release-asset or repo-branch strategy is used
- THEN it SHALL use the token for authentication
- GIVEN neither
GITHUB_TOKENnorGH_TOKENis set - AND the user has authenticated via the GitHub CLI (
gh auth login) - WHEN the release-asset or repo-branch strategy is used (whether selected explicitly via
--strategyor chosen from the default order) - THEN the system SHALL fall back to the token returned by
gh auth token, preferring an account that can access the target repository - AND it SHALL only emit
Strategy '<name>' is not availablewhen neither an environment token nor a usable GitHub CLI token can be resolved
- GIVEN
GH_ATTACH_STATE_PATHenvironment variable - THEN it SHALL override the default session state file location
- GIVEN
GH_ATTACH_STRATEGYenvironment variable - THEN it SHALL override the default strategy selection
The system SHALL be usable as a CLI tool via Docker container.
- GIVEN the Docker image
ghcr.io/addono/gh-attach - WHEN a user runs:
docker run -e GITHUB_TOKEN=ghp_xxx -v $(pwd):/workspace ghcr.io/addono/gh-attach upload /workspace/screenshot.png --target owner/repo#42 - THEN it SHALL upload the image and print the markdown embed to stdout
- GIVEN the Docker image
- WHEN a user runs:
cat screenshot.png | docker run -i -e GITHUB_TOKEN=ghp_xxx ghcr.io/addono/gh-attach upload --target owner/repo#42 --stdin --filename screenshot.png - THEN it SHALL read from stdin and upload the image