gh-arc
🚧 Fork in progress, expect some dust 🚧

gh-arc is a github cli extension that implements an opinionated trunk-based development workflow with Github, built upon the great traditions of tools like phacility/arcanist and phorge/arcanist.
[!TIP]
Check out this DORA Trunk-based development page if, by any chance, this is the first time you're hearing about it and interested to learn more about about this methodology.
[!WARNING]
This project was created with the help of Claude-Code and I'm using it as a "pet project" to try out different CC workflows. That said, I try (yeah, I know, "do or do not...", but you know, our desires don't always conicide with our possibiltiies) not to compromise on quality and testing. I also use this extension daily when working with github code reviews. That said, if you have any problems with code that is written by AI - you've been warned.
Installation
Install the latest release using the GitHub CLI:
gh extension install serpro69/gh-arc
Installation from Source
git clone https://github.com/serpro69/gh-arc.git
cd gh-arc && go build . && gh extension install .
[!TIP]
Clone the repo to a permanent location, gh cli will alias the binary when you run gh extension install . command.
Usage
Authentication
gh-arc requires GitHub CLI authentication with specific OAuth scopes to access user information and repository data. The required additional scopes are:
user:email - Access to user email addresses
read:user - Read user profile data
Setting up authentication
If you're already logged in to GitHub CLI, refresh your token with the additional required scopes:
gh auth refresh --scopes "user:email,read:user"
If you're not logged in, authenticate with the additional required scopes:
gh auth login --scopes "user:email,read:user"
Alternatively, you can provide your own personal access token:
echo "your-token-here" | gh auth login --with-token
[!NOTE]
Personal access tokens must include the user:email and read:user scopes, in addition to the scopes needed by gh cli itself, to work with gh-arc.
To verify your authentication and scopes:
gh arc auth
Commands Overview
gh-arc is a "wrapper" that sits on top of other tools: Github (naturally, being a github-cli extension) and Linear (if you use it for issue management instead of Github), but also linters, formatters, unit test frameworks and others. It provides a simple command-line API to manage code review and some related revision control operations.
For a detailed list of all available commands, run:
gh arc help
For detailed information about a specific command, run:
gh arc help <command>
In a gist, gh arc allows you to do things like:
- get detailed help about available commands with
gh arc help
- create a new, short-lived, feature branch from an up-to-date
origin/HEAD with gh arc work
- send your code to Github for review with
gh arc diff
- show pending revision information with
gh arc list
- find likely reviewers for a change with
gh arc cover
- apply changes in a revision to the working copy with
gh arc patch
- download a patch from Github with
gh arc export
- update Git commit messages after review with
gh arc amend
- push changes with
gh arc land
- view enhanced information about Git branches with
gh arc branch
Once you've configured lint and unit test integration, you can also:
- check your code for syntax and style errors with
gh arc lint
- run unit tests that cover your changes with
gh arc unit
This extension also integrates with other tools:
- create and view github gists with
gh arc gist
It has some advanced features as well, you can:
- enable tab completion with
gh arc completion
- ...or extend the extension and add new commands
Shell Completion
Github CLI does not currently support shell completion for extensions (See cli/cli#5309), but even if it did, who wants to type gh arc <TAB> <TAB> <TAB> ...that's just too much work if you ask me 🤷
So we've come up with a "simple as a rock" (is that a thing? 🤔) solution to both of the above problems 💡
-
Find out where github cli installs extensions on your machine. On Linux (and maybe on Mac), it's usually under ~/.local/share/gh/extensions.
-
Create a simple arc shell script file with the following contents:
#!/usr/bin/env bash
# Simple wrapper to enable completions for 'gh-arc' extension
gh arc "$@"
-
Make it executable and place it on your PATH.
-
Get the completion script for your shell from the releases page. Don't forget to source it or whatever, you know what to do.
-
Then try typing arc <TAB> ...you should see the command completion for the extension; and as an added bonus, you've shortened the overall gh ... command as well... 🤯 Who said ingenious can't be simple?
-
Profit... ⏱️
Configuration
gh-arc can be configured using either JSON or YAML configuration files. The extension looks for configuration files in the following locations (in order of precedence):
- Current directory:
./.arc.json, ./.arc.yaml, or ./.arc.yml
- User config:
~/.config/gh-arc/.arc.json, ~/.config/gh-arc/.arc.yaml, or ~/.config/gh-arc/.arc.yml
- System-wide:
/etc/gh-arc/.arc.json, /etc/gh-arc/.arc.yaml, or /etc/gh-arc/.arc.yml
Within each directory, JSON files take precedence over YAML files (.arc.json > .arc.yaml > .arc.yml).
A JSON Schema is available for editor autocompletion and validation. For .arc.json, add the $schema key as shown below. For YAML, configure your editor's YAML language server to associate the schema with .arc.yaml/.arc.yml files.
Create a .arc.json or .arc.yaml file in your project root or user config directory:
JSON format (.arc.json):
{
"$schema": "https://raw.githubusercontent.com/serpro69/gh-arc/main/docs/arc.schema.json",
"github": {
"defaultBranch": "main",
"defaultReviewers": [],
"autoAssignReviewer": false
},
"diff": {
"createAsDraft": true,
"autoUpdatePR": true,
"includeCommitMessages": true,
"enableStacking": true,
"defaultBase": "",
"showStackingWarnings": true,
"templatePath": "",
"requireTestPlan": true,
"linearEnabled": false,
"linearDefaultProject": ""
},
"land": {
"defaultMergeMethod": "squash",
"deleteLocalBranch": true,
"requireApproval": "strict",
"requireCI": "required"
},
"output": {
"verbose": false,
"quiet": false,
"json": false,
"color": true
}
}
YAML format (.arc.yaml or .arc.yml):
github:
defaultBranch: main
defaultReviewers: []
autoAssignReviewer: false
diff:
createAsDraft: true
autoUpdatePR: true
includeCommitMessages: true
enableStacking: true
defaultBase: ""
showStackingWarnings: true
templatePath: ""
requireTestPlan: true
linearEnabled: false
linearDefaultProject: ""
land:
defaultMergeMethod: squash
deleteLocalBranch: true
requireApproval: strict
requireCI: required
output:
verbose: false
quiet: false
json: false
color: true
Configuration Options
GitHub Settings
github.defaultBranch (string, default: "main"): The default base branch for new PRs
github.defaultReviewer (string, default: ""): Default reviewer to assign to PRs
github.autoAssignReviewer (bool, default: false): Automatically assign the default reviewer to new PRs
Diff (PR Creation) Settings
diff.createAsDraft (bool, default: true): Create PRs as drafts by default
diff.autoUpdatePR (bool, default: true): Automatically update existing PRs when running gh arc diff
diff.includeCommitMessages (bool, default: true): Include commit messages in PR description
diff.enableStacking (bool, default: true): Enable automatic stacked PR detection
diff.defaultBase (string, default: ""): Force a specific base branch (empty = auto-detect)
diff.showStackingWarnings (bool, default: true): Show warnings when dependent PRs exist
diff.templatePath (string, default: ""): Path to custom PR template (empty = use built-in)
diff.requireTestPlan (bool, default: true): Require test plan in PR template
diff.linearEnabled (bool, default: false): Enable Linear issue integration
diff.linearDefaultProject (string, default: ""): Default Linear project for issue references
Land (Merge) Settings
land.defaultMergeMethod (string, default: "squash"): Default merge method (squash or rebase)
land.deleteLocalBranch (bool, default: true): Delete local branch after landing
land.requireApproval (string, default: "strict"): Approval check mode — "strict" (block, --force to bypass), "prompt" (interactive confirmation), "none" (skip)
land.requireCI (string, default: "required"): CI check mode — "required" (only branch-protection required checks), "all" (every check must pass), "none" (skip)
Output Settings
output.verbose (bool, default: false): Enable verbose output
output.quiet (bool, default: false): Suppress non-essential output
output.json (bool, default: false): Output results in JSON format
output.color (bool, default: true): Enable colored output
Environment Variables
All configuration options can be overridden using environment variables with the GHARC_ prefix. Use underscores to separate nested keys:
# Override diff.createAsDraft
export GHARC_DIFF_CREATEASDRAFT=false
# Override github.defaultBranch
export GHARC_GITHUB_DEFAULTBRANCH=master
# Override land.defaultMergeMethod
export GHARC_LAND_DEFAULTMERGEMETHOD=rebase
Advanced Configuration
Test Runners
Configure custom test runners in your .arc.json:
{
"test": {
"runners": [
{
"name": "go-test",
"command": "go",
"args": ["test", "./..."],
"workingDir": "",
"timeout": "5m"
}
]
}
}
Lint Runners
Configure custom linters:
{
"lint": {
"runners": [
{
"name": "golangci-lint",
"command": "golangci-lint",
"args": ["run"],
"workingDir": "",
"autoFix": true
}
],
"megaLinter": {
"enabled": "auto",
"config": ".mega-linter.yml",
"fixIssues": false
}
}
}
Example: Minimal Configuration
For most projects, you only need to override a few settings:
JSON (.arc.json):
{
"diff": {
"createAsDraft": false,
"requireTestPlan": false
}
}
YAML (.arc.yaml):
diff:
createAsDraft: false
requireTestPlan: false
This configuration:
- Creates PRs as ready-for-review by default
- Makes the test plan field optional
All other settings will use their default values.