{"meta":{"title":"Creating GitHub CLI extensions","intro":"Learn how to share new GitHub CLI commands with other users by creating custom extensions for GitHub CLI.","product":"GitHub CLI","breadcrumbs":[{"href":"/en/github-cli","title":"GitHub CLI"},{"href":"/en/github-cli/github-cli","title":"GitHub CLI"},{"href":"/en/github-cli/github-cli/creating-github-cli-extensions","title":"Creating GitHub CLI extensions"}],"documentType":"article"},"body":"# Creating GitHub CLI extensions\n\nLearn how to share new GitHub CLI commands with other users by creating custom extensions for GitHub CLI.\n\n## About GitHub CLI extensions\n\nGitHub CLI extensions are custom GitHub CLI commands that anyone can create and use. For more information about how to use GitHub CLI extensions, see [Using GitHub CLI extensions](/en/github-cli/github-cli/using-github-cli-extensions).\n\nYou need a repository for each extension that you create. The repository name must start with `gh-`. The rest of the repository name is the name of the extension. The repository must have an executable file at its root with the same name as the repository or a set of precompiled binary executables attached to a release.\n\n> \\[!NOTE]\n> When relying on an executable script, we recommend using a bash script because bash is a widely available interpreter. You may use non-bash scripts, but the user must have the necessary interpreter installed in order to use the extension. If you would prefer to not rely on users having interpreters installed, consider a precompiled extension.\n\n## Creating an interpreted extension with `gh extension create`\n\n> \\[!NOTE]\n> Running `gh extension create` with no arguments will start an interactive wizard.\n\nYou can use the `gh extension create` command to create a project for your extension, including a bash script that contains some starter code.\n\n1. Set up a new extension by using the `gh extension create` subcommand. Replace `EXTENSION-NAME` with the name of your extension.\n\n   ```shell\n   gh extension create EXTENSION-NAME\n   ```\n\n2. Follow the printed instructions to finalize and optionally publish your extension.\n\n## Creating a precompiled extension in Go with `gh extension create`\n\nYou can use the `--precompiled=go` argument to create a Go-based project for your extension, including Go scaffolding, workflow scaffolding, and starter code.\n\n1. Set up a new extension by using the `gh extension create` subcommand. Replace `EXTENSION-NAME` with the name of your extension and specify `--precompiled=go`.\n\n   ```shell\n   gh extension create --precompiled=go EXTENSION-NAME\n   ```\n\n2. Follow the printed instructions to finalize and optionally publish your extension.\n\n## Creating a non-Go precompiled extension with `gh extension create`\n\nYou can use the `--precompiled=other` argument to create a project for your non-Go precompiled extension, including workflow scaffolding.\n\n1. Set up a new extension by using the `gh extension create` subcommand. Replace `EXTENSION-NAME` with the name of your extension and specify `--precompiled=other`.\n\n   ```shell\n   gh extension create --precompiled=other EXTENSION-NAME\n   ```\n\n2. Add some initial code for your extension in your compiled language of choice.\n\n3. Fill in `script/build.sh` with code to build your extension to ensure that your extension can be built automatically.\n\n4. Follow the printed instructions to finalize and optionally publish your extension.\n\n## Creating an interpreted extension manually\n\n1. Create a local directory called `gh-EXTENSION-NAME` for your extension. Replace `EXTENSION-NAME` with the name of your extension. For example, `gh-whoami`.\n\n2. In the directory that you created, add an executable file with the same name as the directory.\n\n   > \\[!NOTE]\n   > Make sure that your file is executable. On Unix, you can execute `chmod +x file_name` in the command line to make `file_name` executable. On Windows, you can run `git init -b main`, `git add file_name`, then `git update-index --chmod=+x file_name`.\n\n3. Write your script in the executable file. For example:\n\n   ```bash\n   #!/usr/bin/env bash\n   set -e\n   exec gh api user --jq '\"You are @\\(.login) (\\(.name)).\"'\n   ```\n\n4. From your directory, install the extension as a local extension.\n\n   ```shell\n   gh extension install .\n   ```\n\n5. Verify that your extension works. Replace `EXTENSION-NAME` with the name of your extension. For example, `whoami`.\n\n   ```shell\n   gh EXTENSION-NAME\n   ```\n\n6. From your directory, create a repository to publish your extension. Replace `EXTENSION-NAME` with the name of your extension.\n\n   ```shell\n   git init -b main\n   git add . && git commit -m \"initial commit\"\n   gh repo create gh-EXTENSION-NAME --source=. --public --push\n   ```\n\n7. Optionally, to help other users discover your extension, add the repository topic `gh-extension`. This will make the extension appear on the [`gh-extension` topic page](https://github.com/topics/gh-extension). For more information about how to add a repository topic, see [Classifying your repository with topics](/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics).\n\n## Tips for writing interpreted GitHub CLI extensions\n\n### Handling arguments and flags\n\nAll command line arguments following a `gh my-extension-name` command will be passed to the extension script. In a bash script, you can reference arguments with `$1`, `$2`, etc. You can use arguments to take user input or to modify the behavior of the script.\n\nFor example, this script handles multiple flags. When the script is called with the `-h` or `--help` flag, the script prints help text instead of continuing execution. When the script is called with the `--name` flag, the script sets the next value after the flag to `name_arg`. When the script is called with the `--verbose` flag, the script prints a different greeting.\n\n```bash\n#!/usr/bin/env bash\nset -e\n\nverbose=\"\"\nname_arg=\"\"\nwhile [ $# -gt 0 ]; do\n  case \"$1\" in\n  --verbose)\n    verbose=1\n    ;;\n  --name)\n    name_arg=\"$2\"\n    shift\n    ;;\n  -h|--help)\n    echo \"Add help text here.\"\n    exit 0\n    ;;\n  esac\n  shift\ndone\n\nif [ -z \"$name_arg\" ]\nthen\n  echo \"You haven't told us your name.\"\nelif [ -z \"$verbose\" ]\nthen\n  echo \"Hi $name_arg\"\nelse\n  echo \"Hello and welcome, $name_arg\"\nfi\n```\n\n### Calling core commands in non-interactive mode\n\nSome GitHub CLI core commands will prompt the user for input. When scripting with those commands, a prompt is often undesirable. To avoid prompting, supply the necessary information explicitly via arguments.\n\nFor example, to create an issue programmatically, specify the title and body:\n\n```shell\ngh issue create --title \"My Title\" --body \"Issue description\"\n```\n\n### Fetching data programmatically\n\nMany core commands support the `--json` flag for fetching data programmatically. For example, to return a JSON object listing the number, title, and mergeability status of pull requests:\n\n```shell\ngh pr list --json number,title,mergeStateStatus\n```\n\nIf there is not a core command to fetch specific data from GitHub, you can use the [`gh api`](https://cli.github.com/manual/gh_api) command to access the GitHub API. For example, to fetch information about the current user:\n\n```shell\ngh api user\n```\n\nAll commands that output JSON data also have options to filter that data into something more immediately usable by scripts. For example, to get the current user's name:\n\n```shell\ngh api user --jq '.name'\n```\n\nFor more information, see [`gh help formatting`](https://cli.github.com/manual/gh_help_formatting).\n\n## Creating a precompiled extension manually\n\n1. Create a local directory called `gh-EXTENSION-NAME` for your extension. Replace `EXTENSION-NAME` with the name of your extension. For example, `gh-whoami`.\n\n2. In the directory you created, add some source code. For example:\n\n   ```golang\n   package main\n   import (\n     \"github.com/cli/go-gh\"\n     \"fmt\"\n   )\n\n   func main() {\n     args := []string{\"api\", \"user\", \"--jq\", `\"You are @\\(.login) (\\(.name))\"` }\n     stdOut, _, err := gh.Exec(args...)\n     if err != nil {\n       fmt.Println(err)\n       return\n     }\n     fmt.Println(stdOut.String())\n   }\n   ```\n\n3. From your directory, install the extension as a local extension.\n\n   ```shell\n   gh extension install .\n   ```\n\n4. Build your code. For example, with Go, replacing `YOUR-USERNAME` with your GitHub username:\n\n   ```shell\n   go mod init github.com/YOUR-USERNAME/gh-whoami\n   go mod tidy\n   go build\n   ```\n\n5. Verify that your extension works. Replace `EXTENSION-NAME` with the name of your extension. For example, `whoami`.\n\n   ```shell\n   gh EXTENSION-NAME\n   ```\n\n6. From your directory, create a repository to publish your extension. Replace `EXTENSION-NAME` with the name of your extension.\n\n   > \\[!NOTE]\n   > Be careful not to commit the binary produced by your compilation step to version control.\n\n   ```shell\n    git init -b main\n   echo \"gh-EXTENSION-NAME\" >> .gitignore\n   git add main.go go.* .gitignore && git commit -m 'Initial commit'\n   gh repo create \"gh-EXTENSION-NAME\"\n   ```\n\n7. Create a release to share your precompiled extension with others. Compile for each platform you want to support, attaching each binary to a release as an asset. Binary executables attached to releases must follow a naming convention and have a suffix of OS-ARCHITECTURE\\[EXTENSION].\n\n   For example, an extension named `whoami` compiled for Windows 64bit would have the name `gh-whoami-windows-amd64.exe` while the same extension compiled for Linux 32bit would have the name `gh-whoami-linux-386`. To see an exhaustive list of OS and architecture combinations recognized by `gh`, see [this source code](https://github.com/cli/cli/blob/14f704fd0da58cc01413ee4ba16f13f27e33d15e/pkg/cmd/extension/manager.go#L696).\n\n   > \\[!NOTE]\n   > For your extension to run properly on Windows, its asset file must have a `.exe` extension. No extension is needed for other operating systems.\n\n   Releases can be created from the command line. For example:\n\n   ```shell\n   git tag v1.0.0\n   git push origin v1.0.0\n   GOOS=windows GOARCH=amd64 go build -o gh-EXTENSION-NAME-windows-amd64.exe\n   GOOS=linux GOARCH=amd64 go build -o gh-EXTENSION-NAME-linux-amd64\n   GOOS=darwin GOARCH=amd64 go build -o gh-EXTENSION-NAME-darwin-amd64\n   gh release create v1.0.0 ./*amd64*\n\n   ```\n\n8. Optionally, to help other users discover your extension, add the repository topic `gh-extension`. This will make the extension appear on the [`gh-extension` topic page](https://github.com/topics/gh-extension). For more information about how to add a repository topic, see [Classifying your repository with topics](/en/github/administering-a-repository/managing-repository-settings/classifying-your-repository-with-topics).\n\n## Tips for writing precompiled GitHub CLI extensions\n\n### Automating releases\n\nConsider adding the [gh-extension-precompile](https://github.com/cli/gh-extension-precompile) action to a workflow in your project. This action will automatically produce cross-compiled Go binaries for your extension and supplies build scaffolding for non-Go precompiled extensions.\n\n### Using GitHub CLI features from Go-based extensions\n\nConsider using [go-gh](https://github.com/cli/go-gh), a Go library that exposes pieces of `gh` functionality for use in extensions.\n\n## Next steps\n\nTo see more examples of GitHub CLI extensions, look at [repositories with the `gh-extension` topic](https://github.com/topics/gh-extension)."}