| 1 | --- |
| 2 | title: The g1t CLI |
| 3 | description: Install the g1t command line, sign in, and work with repositories, issues, pull requests, runs, workflows, deployments, secrets and logs from a terminal, a script or an agent. |
| 4 | --- |
| 5 | |
| 6 | `g1t` is the command line for g1t. It does the work you would otherwise do on |
| 7 | the site: open and review pull requests, wait on checks, read a failing run's |
| 8 | logs, set secrets, read a project's logs, and call any operation of the |
| 9 | [API](/reference/api/). It is one file with nothing to install alongside it, |
| 10 | and it is built to be run by agents as much as by people: every command can |
| 11 | print JSON, nothing waits for input unless a person is at the terminal, and |
| 12 | exit codes say what happened. |
| 13 | |
| 14 | ```sh |
| 15 | g1t issue list --label bug |
| 16 | g1t pr create --fill |
| 17 | g1t pr checks --watch --fail-fast |
| 18 | g1t run logs --failed |
| 19 | ``` |
| 20 | |
| 21 | Every command and flag is listed in the [command reference](/reference/cli/). |
| 22 | |
| 23 | ## Install |
| 24 | |
| 25 | On Linux or macOS: |
| 26 | |
| 27 | ```sh |
| 28 | curl -fsSL https://g1t.sh/install | sh |
| 29 | ``` |
| 30 | |
| 31 | On Windows, in PowerShell: |
| 32 | |
| 33 | ```powershell |
| 34 | irm https://g1t.sh/install.ps1 | iex |
| 35 | ``` |
| 36 | |
| 37 | The script picks the build for your system, checks it against the |
| 38 | release's `SHA256SUMS`, and puts `g1t` in `~/.local/bin` (Windows: |
| 39 | `%LOCALAPPDATA%\g1t\bin`, which it adds to your `PATH`). Set |
| 40 | `G1T_INSTALL_DIR` to put it elsewhere, or `G1T_VERSION` to install a |
| 41 | version other than the latest. Run it again to update. |
| 42 | |
| 43 | ### Without the script |
| 44 | |
| 45 | Each release is a single file per platform, at |
| 46 | `https://g1t.sh/downloads/cli/latest/`: |
| 47 | |
| 48 | | Platform | File | |
| 49 | | --- | --- | |
| 50 | | Linux, x64 | `g1t-linux-x64` | |
| 51 | | Linux, ARM | `g1t-linux-arm64` | |
| 52 | | macOS, Apple silicon | `g1t-macos-arm64` | |
| 53 | | macOS, Intel | `g1t-macos-x64` | |
| 54 | | Windows, x64 | `g1t-windows-x64.exe` | |
| 55 | |
| 56 | ```sh |
| 57 | curl -fsSLo g1t https://g1t.sh/downloads/cli/latest/g1t-linux-x64 |
| 58 | chmod +x g1t && mv g1t ~/.local/bin/ |
| 59 | ``` |
| 60 | |
| 61 | Check a download against `https://g1t.sh/downloads/cli/latest/SHA256SUMS`. |
| 62 | `latest.json` beside it names the version and each file's SHA-256, and |
| 63 | `latest.json.sig` is its signature. A given version's files are at |
| 64 | `/downloads/cli/<version>/` and never change. |
| 65 | |
| 66 | To build it from source, with [Rust](https://www.rust-lang.org/tools/install): |
| 67 | |
| 68 | ```sh |
| 69 | git clone https://g1t.sh/flagon-io/g1t |
| 70 | cargo install --path g1t/crates/g1t |
| 71 | ``` |
| 72 | |
| 73 | `g1t --version` prints the version you have. |
| 74 | |
| 75 | ## Sign in |
| 76 | |
| 77 | ```sh |
| 78 | g1t auth login |
| 79 | ``` |
| 80 | |
| 81 | `g1t` shows a one-time code and opens your browser at |
| 82 | [g1t.sh/device](https://g1t.sh/device). Sign in there if you are not |
| 83 | already, check the code matches, and approve. The command finishes on its |
| 84 | own once you have. Where there is no browser (a server, a container, a |
| 85 | remote shell), it prints the link instead: open it on any device. |
| 86 | |
| 87 | To use an [access token](/guides/authentication/#access-tokens) you already |
| 88 | have, pipe it in: |
| 89 | |
| 90 | ```sh |
| 91 | g1t auth login --with-token < token.txt |
| 92 | ``` |
| 93 | |
| 94 | The token is kept in your system's credential store: the Keychain on |
| 95 | macOS, Credential Manager on Windows, the Secret Service on Linux. Where |
| 96 | there is none, as on most servers, it goes in the [config |
| 97 | file](#settings-and-environment), readable only by you; `--insecure-storage` |
| 98 | puts it there on purpose. |
| 99 | |
| 100 | | Command | What it does | |
| 101 | | --- | --- | |
| 102 | | `g1t auth status` | Each account you are signed in as, on each host, whether its token still works, and its scopes. Exits `4` when the active account's token does not work. | |
| 103 | | `g1t auth token` | Prints the token in use, for another program. | |
| 104 | | `g1t auth logout` | Forgets an account's token. | |
| 105 | | `g1t auth switch` | Makes another signed-in account on the same host the active one. | |
| 106 | |
| 107 | ### G1T_TOKEN |
| 108 | |
| 109 | When `G1T_TOKEN` is set, every command uses it instead of a stored token. |
| 110 | This is how to give `g1t` a token in containers, in agents' sandboxes, and |
| 111 | in [workflows](/guides/actions/), where the job's own token is |
| 112 | `secrets.G1T_TOKEN`: |
| 113 | |
| 114 | ```yaml |
| 115 | - run: g1t pr comment ${{ github.event.pull_request.number }} -b "Preview is up." |
| 116 | env: |
| 117 | G1T_TOKEN: ${{ secrets.G1T_TOKEN }} |
| 118 | ``` |
| 119 | |
| 120 | ### Self-hosted g1t |
| 121 | |
| 122 | `g1t` works with any g1t, not only g1t.sh. Sign in to yours with its |
| 123 | address: |
| 124 | |
| 125 | ```sh |
| 126 | g1t auth login --hostname git.example.com |
| 127 | ``` |
| 128 | |
| 129 | `g1t` asks it where its API is (its `/.well-known/g1t.json`), and remembers. |
| 130 | After that, commands in a clone of one of its repositories talk to it on |
| 131 | their own. Elsewhere, name it with `--hostname` or `G1T_HOST`; the first host |
| 132 | you sign in to is the default. You can be signed in to several hosts, and |
| 133 | as several accounts on each. |
| 134 | |
| 135 | ## Use it with git |
| 136 | |
| 137 | ```sh |
| 138 | g1t auth setup-git |
| 139 | ``` |
| 140 | |
| 141 | This makes `g1t` git's credential helper for each host you are signed in |
| 142 | to, so `git push`, `git fetch` and `git clone` over HTTPS use the same |
| 143 | token, with nothing more to type. It changes your global git config only for |
| 144 | those hosts' addresses (`credential.https://g1t.sh.helper`). `g1t auth login |
| 145 | --git` does both at once. To see the config lines without changing anything, |
| 146 | add `--dry-run`. |
| 147 | |
| 148 | [`g1t push`](/guides/containers/#push-large-layers-with-g1t-push), which sends container |
| 149 | images to g1t's registry, uses the same signed-in token. |
| 150 | |
| 151 | ## Which repository |
| 152 | |
| 153 | Commands about a repository work on the one the current directory is a |
| 154 | clone of, found from its git remotes: `upstream` if it is on g1t, then |
| 155 | `origin`, then the first one that is. In a pull request's own [working |
| 156 | copy](/guides/pull-requests/), they work on the repository the pull request |
| 157 | is for. |
| 158 | |
| 159 | Anywhere else, or to choose another, pass `--repo` (`-R`), or set |
| 160 | `G1T_REPO`: |
| 161 | |
| 162 | ```sh |
| 163 | g1t issue list -R acme/web |
| 164 | g1t pr view 14 -R git.example.com/acme/web |
| 165 | ``` |
| 166 | |
| 167 | ## Everyday work |
| 168 | |
| 169 | ### Issues |
| 170 | |
| 171 | ```sh |
| 172 | g1t issue list # open issues, newest first |
| 173 | g1t issue list --label bug --assignee @me |
| 174 | g1t issue view 12 --comments |
| 175 | g1t issue create -t "Greeting should name the caller" -b "Take a name from the first argument." |
| 176 | g1t issue comment 12 -b "Fixed in #14." |
| 177 | g1t issue edit 12 --add-label p1 --add-assignee @me |
| 178 | g1t issue close 12 --reason not_planned |
| 179 | ``` |
| 180 | |
| 181 | `@me` is you. At a terminal, `g1t issue create` without `--title` asks for |
| 182 | one and opens your editor for the body. |
| 183 | |
| 184 | ### Pull requests |
| 185 | |
| 186 | From a branch with your commits on it: |
| 187 | |
| 188 | ```sh |
| 189 | git switch -c greet-by-name |
| 190 | # ...commit... |
| 191 | g1t pr create --fill --issue 12 |
| 192 | ``` |
| 193 | |
| 194 | `g1t pr create` pushes the branch, then opens the pull request into the |
| 195 | default branch (`--base` for another). `--fill` takes the title and body from |
| 196 | the branch's commits; `--issue` says which issue it is for; `--draft` opens |
| 197 | it as a draft. |
| 198 | |
| 199 | To start a pull request for an issue without a branch of your own, as g1t's |
| 200 | agents do, run it with `--issue` from the default branch. g1t opens a draft |
| 201 | with a [working copy](/guides/pull-requests/) of its own and prints the |
| 202 | copy's git remote. Push your commits there, then mark it ready with a |
| 203 | summary of what changed and why: |
| 204 | |
| 205 | ```sh |
| 206 | g1t pr create --issue 12 |
| 207 | git push https://g1t.sh/pulls/pr_….git HEAD:main |
| 208 | g1t pr ready --summary "Reads a name from the first argument." |
| 209 | ``` |
| 210 | |
| 211 | Then, for any pull request: |
| 212 | |
| 213 | ```sh |
| 214 | g1t pr list |
| 215 | g1t pr view 14 # the current branch's when left out |
| 216 | g1t pr diff 14 |
| 217 | g1t pr checkout 14 # check its head out locally |
| 218 | g1t pr checks 14 --watch |
| 219 | g1t pr review 14 --approve -b "Reads well." |
| 220 | g1t pr review 14 --request-changes -b "Trim the name first." |
| 221 | g1t pr merge 14 --delete-branch |
| 222 | ``` |
| 223 | |
| 224 | `g1t pr merge` merges the way the repository is set to, once |
| 225 | [required checks](/guides/checks/) pass and [rules](/guides/rules/) allow; |
| 226 | `--admin` merges past them, with the Admin role. |
| 227 | |
| 228 | ### Checks and runs |
| 229 | |
| 230 | `g1t pr checks` lists a pull request's checks: g1t Actions jobs, check runs |
| 231 | and commit statuses. With `--watch` it waits until they have all finished, |
| 232 | redrawing at a terminal and printing a line per change when piped. |
| 233 | `--fail-fast` stops at the first failure instead of waiting for the rest. It |
| 234 | exits `0` when every check passed, `1` when one failed, and, without |
| 235 | `--watch`, `8` while any are still running. |
| 236 | |
| 237 | ```sh |
| 238 | g1t run list --branch main |
| 239 | g1t run view # the current branch's latest run |
| 240 | g1t run watch run_01kpx7b3c6d9e2f5g8h1j4k7mr |
| 241 | g1t run logs --failed |
| 242 | g1t run rerun --failed |
| 243 | ``` |
| 244 | |
| 245 | A run is named by its id (`run_…`), its number, or its address; left out, |
| 246 | it is the current branch's latest. `g1t run logs --failed` prints only the |
| 247 | steps that failed, each with its last 60 lines (`-n` for more or fewer): |
| 248 | what you need to see why, without the rest of the log. `g1t run watch` |
| 249 | exits `1` if the run fails. |
| 250 | |
| 251 | ### Workflows |
| 252 | |
| 253 | `g1t workflow` works with the workflows in `.g1t/workflows`, as the |
| 254 | repository's **Actions** page does. |
| 255 | |
| 256 | ```sh |
| 257 | g1t workflow list # those turned on; --all for every one |
| 258 | g1t workflow view ci.yml # its triggers, inputs and latest runs |
| 259 | g1t workflow view release.yml --yaml --ref v1.4.0 |
| 260 | g1t workflow run release.yml -f channel=stable |
| 261 | g1t workflow disable Nightly |
| 262 | g1t workflow enable nightly.yml |
| 263 | ``` |
| 264 | |
| 265 | A workflow is named by its file name (`ci.yml`), its id (`wfl_…`) or its |
| 266 | name (`CI`, in any case). When more than one has that name, name it by its |
| 267 | file. Left out at a terminal, g1t asks which; in a script it is an error |
| 268 | that names what to pass. |
| 269 | |
| 270 | `g1t workflow run` runs a workflow that has `on: workflow_dispatch`, on the |
| 271 | default branch or the branch or tag `--ref` names, and prints its run's |
| 272 | address once the run is there, so `g1t run watch` can follow it. Give its |
| 273 | inputs with `-f key=value` (or `-F key=@file` to read a value from a file), |
| 274 | or as one JSON object on stdin with `--json`: |
| 275 | |
| 276 | ```sh |
| 277 | echo '{"channel":"stable","dry_run":true}' | g1t workflow run release.yml --json |
| 278 | ``` |
| 279 | |
| 280 | At a terminal with no inputs given, g1t asks for each, offering its |
| 281 | default. Only the inputs the workflow declares are taken, as on the |
| 282 | [Actions page](/guides/actions/#runs-and-logs). `g1t workflow view --yaml` |
| 283 | prints the workflow's file as it is on the default branch, or on `--ref`. |
| 284 | Turning a workflow off keeps its file: nothing starts it until it is |
| 285 | turned on again, and a workflow the workspace requires stays on. |
| 286 | |
| 287 | ### Deployments, logs and secrets |
| 288 | |
| 289 | ```sh |
| 290 | g1t deploy list --env production |
| 291 | g1t deploy view dep_01kq8m3t5v7x9z1b3d5f7h9k2m |
| 292 | |
| 293 | g1t logs --since 1h --level error,fatal |
| 294 | g1t logs -q '"payment failed"' --follow |
| 295 | g1t logs --errors --state open |
| 296 | |
| 297 | g1t secret list |
| 298 | echo "$NPM_TOKEN" | g1t secret set NPM_TOKEN |
| 299 | g1t secret set STRIPE_KEY --env production < stripe-key.txt |
| 300 | g1t secret set NPM_TOKEN --brokered-host registry.npmjs.org < npm-token.txt |
| 301 | g1t secret delete STRIPE_KEY --env preview |
| 302 | g1t secret list --workspace acme |
| 303 | ``` |
| 304 | |
| 305 | `g1t logs` reads the [observability](/guides/observability/) data of the |
| 306 | current repository's project, or of `--project WORKSPACE/SLUG`. A secret's |
| 307 | value is read from stdin, so it stays out of your shell's history; at a |
| 308 | terminal with nothing piped, `g1t` asks for it without echoing. Values are |
| 309 | never printed. `--brokered-host` makes it a [brokered |
| 310 | secret](/guides/secrets-and-variables/#brokered-secrets). |
| 311 | |
| 312 | ### What needs you |
| 313 | |
| 314 | ```sh |
| 315 | g1t status |
| 316 | ``` |
| 317 | |
| 318 | Your open pull requests and their checks, reviews asked of you, what is |
| 319 | assigned to you, and failing checks, across every repository you can see. |
| 320 | Inside a working copy it also lists your active sessions and claims in that |
| 321 | repository. |
| 322 | |
| 323 | ## Coordinating work |
| 324 | |
| 325 | When several people and agents work in one repository, `g1t session` and |
| 326 | `g1t work` say who is on what, so nobody starts work that is already under |
| 327 | way and everyone hears what changes under them. Claims are advisory: a |
| 328 | claim never stops anyone, it tells them. |
| 329 | |
| 330 | ### Sessions |
| 331 | |
| 332 | A session is one run of an agent's harness, such as one Claude Code |
| 333 | session. Starting one remembers it for the working copy, and the commands |
| 334 | after it use it: |
| 335 | |
| 336 | ```sh |
| 337 | g1t session start --harness claude-code --issue 12 |
| 338 | g1t session log "Split the parser before touching the lexer." |
| 339 | g1t session attach --pull 14 --head-commit "$(git rev-parse HEAD)" |
| 340 | g1t session heartbeat |
| 341 | g1t session end --reason done |
| 342 | ``` |
| 343 | |
| 344 | | Command | What it does | |
| 345 | | --- | --- | |
| 346 | | `g1t session start` | Starts a session and prints its id. `--harness` (`claude_code`, `codex`, `cursor`, `copilot` or `other`; `claude-code` works too; `claude_managed_agents` is only for the sessions g1t starts itself, with `g1t work dispatch`), `--harness-session-id`, `--issue`, `--pull`, `--branch` (the current one by default) and `--title`. Starting again with the same `--harness-session-id` returns the same session. For a subagent, `--parent` (the session that started it), `--agent-type`, `--task`, `--prompt` and `--model`; a subagent's session is not kept as the working copy's (nor is one with `--no-remember`). | |
| 347 | | `g1t session heartbeat` | Says the session is still working, and renews its claims. A session with no heartbeat for 15 minutes reads as idle, and after 2 hours as ended. | |
| 348 | | `g1t session log TEXT` | Records a note. `--kind` takes `note`, `prompt`, `message`, `tool_call` (or `tool-call`) or `skill` (a skill's name), `--tool` names the tool, and `--key` makes recording the same entry twice do nothing. `-` reads the text from stdin; put `--` before text that starts with a dash. | |
| 349 | | `g1t session attach` | Points the session at an `--issue`, a `--pull`, a `--branch` or its latest `--head-commit`, or gives it a `--title`: what it is for, which replaces the title it had. | |
| 350 | | `g1t session touch` | Says what the session touched: `--file PATH`, `--commit SHA`, `--branch NAME`, `--pull N` (one it opened), `--issue N`, each repeatable. Ties the session to the pull requests and issues they lead to; a file another active session touched too is an `overlap.detected` for both. | |
| 351 | | `g1t session end` | Ends it, with an optional `--reason` and `--result` (what it reported; `-` reads it from stdin), and forgets it. Its subagents still going end with it. | |
| 352 | | `g1t session list` | The repository's sessions; `--state active`, `--issue`, `--pull` (any session tied to it), `--path` (those that touched a file, or a folder ending in `/`), `--subagents` to list subagents under the sessions that started them. | |
| 353 | | `g1t session view [ID]` | A session and what it recorded, its subagents and their results, the issues and pull requests it worked on, and the skills used; the current one without an id. | |
| 354 | |
| 355 | The id is kept in `.git/g1t/session`, in the working copy's own git |
| 356 | directory, so each worktree has its own. `G1T_SESSION` overrides it, for |
| 357 | a harness that runs several sessions in one working copy. |
| 358 | |
| 359 | ### Claims and context |
| 360 | |
| 361 | ```sh |
| 362 | g1t work context 12 # everything about #12's work |
| 363 | g1t work claim 12 --note "Taking the parser" --ttl 1h |
| 364 | g1t work claim --title "Preview builds time out" --body "Over 1 GB, the build stops at 10 minutes." |
| 365 | g1t work release 12 --reason done |
| 366 | g1t work handoff 12 --to ana --note "Parser done; lexer tests still fail." |
| 367 | g1t work list # active claims and sessions here |
| 368 | ``` |
| 369 | |
| 370 | `g1t work context` is the one call to make before starting: the issue and |
| 371 | its definition of done, who has claimed it, its sessions, its pull |
| 372 | requests with their checks, overlaps and place in the merge queue, what it |
| 373 | waits on and what waits on it, its decisions, its last integration failure |
| 374 | and its recent events. |
| 375 | |
| 376 | `g1t work claim` says you are working on an issue. It lasts 30 minutes |
| 377 | unless `--ttl` says otherwise (at most `4h`), and a heartbeat of the session |
| 378 | it was made in renews it. It is made in the current session, if there is |
| 379 | one. If others have claimed the issue too, or it waits on issues that are |
| 380 | not done, the answer says so. `g1t work handoff` ends your claim and asks |
| 381 | `--to` someone, or anyone without it, to take the issue over, with a |
| 382 | `--note` saying where it stands. Claims, releases and hand-offs are the |
| 383 | current session's, so two sessions of yours (sibling subagents) each hold |
| 384 | their own. |
| 385 | |
| 386 | For work that has no issue yet, `g1t work claim --title "…"` (with |
| 387 | `--body` for its description) opens the issue and claims it in one step, |
| 388 | and attaches the current session to it; it prints the new issue's number. |
| 389 | Use it once the work is a change others should know about, after looking |
| 390 | for an issue that already covers it; questions, exploration and trivial |
| 391 | fixes need none. A number and `--title` together are refused. |
| 392 | |
| 393 | ### Starting a session on an issue |
| 394 | |
| 395 | ```sh |
| 396 | g1t work dispatch 12 # on the workspace's Anthropic account |
| 397 | g1t work dispatch 12 --mode plan --instruction "Keep the old flag" |
| 398 | g1t work dispatch --title "Add a healthcheck" --handoff # open the issue; print a claude command |
| 399 | ``` |
| 400 | |
| 401 | `g1t work dispatch` starts work on an issue in a session on your own |
| 402 | Claude: with the workspace's Anthropic connection, a Claude Managed Agents |
| 403 | session on that account (it prints the session's page on g1t); without |
| 404 | one, or with `--handoff`, the `claude` command line to run in your working |
| 405 | copy with g1t's [Claude Code plugin](/guides/claude-code-plugin/). |
| 406 | `--managed` fails rather than hand off. `--mode` is `plan`, `implement` or |
| 407 | `review`. See [Start a session on your Anthropic account](/guides/sessions/#start-a-session-on-your-anthropic-account). |
| 408 | |
| 409 | ### Dependencies |
| 410 | |
| 411 | ```sh |
| 412 | g1t work block 12 --by 9 --by 10 # #12 waits on #9 and #10 |
| 413 | g1t work unblock 12 --by 9 |
| 414 | ``` |
| 415 | |
| 416 | These change the issue's `blocked_by` through `update_issue`. An issue |
| 417 | cannot wait on itself, and g1t refuses a cycle. |
| 418 | |
| 419 | ### Following events |
| 420 | |
| 421 | `g1t work events` prints the repository's recent events, oldest first. |
| 422 | With `--follow` it keeps printing them as they happen, without a webhook or |
| 423 | a public address, until you stop it with Ctrl-C: |
| 424 | |
| 425 | ```sh |
| 426 | g1t work events --follow --issue 12 |
| 427 | g1t work events --follow --type integration.failed --type overlap.detected --json |
| 428 | ``` |
| 429 | |
| 430 | | Flag | | |
| 431 | | --- | --- | |
| 432 | | `--type`, `-t` | Only events of this type, such as `work.claimed`; repeat for more. | |
| 433 | | `--issue`, `-i` | Only events about this issue or pull request; repeat for more. | |
| 434 | | `--since`, `-s` | Only events since then: `15m`, `2h`, `1d`, or an RFC 3339 time. | |
| 435 | | `--after` | Start after this event id, to resume where an earlier follow stopped. | |
| 436 | | `--limit`, `-L` | How many past events to show first; 20 by default. | |
| 437 | |
| 438 | Each event is one line: its time, type, issue or pull request, a summary |
| 439 | and its id. With `--json`, each is one compact JSON object on a line of its |
| 440 | own, so a program can read them as they come. Following asks |
| 441 | [`list_events`](/reference/api/repositories/list-events/) with `after` and |
| 442 | `wait`, so the server holds each request until something happens; when a |
| 443 | call fails, `g1t` waits (1 second, then longer, up to 30) and resumes from |
| 444 | the last event it printed. A refused token stops it with exit code `4`. |
| 445 | |
| 446 | ### Why a line is as it is |
| 447 | |
| 448 | ```sh |
| 449 | g1t why src/parser.rs:120 |
| 450 | g1t why src/parser.rs --ref main |
| 451 | ``` |
| 452 | |
| 453 | `g1t why` follows a line to the commit that last changed it, the pull |
| 454 | request that merged that commit, the issue the pull request was for, and |
| 455 | the decisions and sessions recorded on them. A path is read from where you |
| 456 | are in the working copy. |
| 457 | |
| 458 | ### In an agent's hooks |
| 459 | |
| 460 | These commands are made to be run by a harness's hooks in the background: |
| 461 | they never ask anything, they fail at once with exit code `4` when there is |
| 462 | no token, and they give up on a call after 15 seconds. Against a g1t server |
| 463 | older than the CLI, a command it cannot do yet fails saying so. |
| 464 | |
| 465 | ## Scripting with JSON |
| 466 | |
| 467 | Every command takes `--json`. Alone, it prints every field the API returns; |
| 468 | with a comma-separated list, only those (`g1t workflow run` is the one |
| 469 | exception: there, `--json` alone reads the inputs from stdin): |
| 470 | |
| 471 | ```sh |
| 472 | g1t pr list --json number,title,check_status |
| 473 | ``` |
| 474 | |
| 475 | ```json |
| 476 | [{"check_status":"passed","number":14,"title":"Greeting should name the caller"}] |
| 477 | ``` |
| 478 | |
| 479 | The fields are the API's own, named as in the [API reference](/reference/api/) |
| 480 | and always `snake_case`. A field that does not exist is an error that lists |
| 481 | the ones that do. Piped, JSON is one compact line with its keys in a fixed |
| 482 | order, so the same input gives the same output; at a terminal it is |
| 483 | indented. |
| 484 | |
| 485 | `--jq` runs a [jq](https://jqlang.org/manual/) expression over the JSON, |
| 486 | with nothing else to install. Strings come out bare, everything else as |
| 487 | JSON: |
| 488 | |
| 489 | ```sh |
| 490 | g1t pr list --jq '.[] | select(.check_status == "failed") | .number' |
| 491 | g1t run list --jq '.[] | [.id, .conclusion] | @tsv' |
| 492 | ``` |
| 493 | |
| 494 | Without `--json`, output piped to another program is one record per line, |
| 495 | fields separated by tabs, with no header and no color, ready for `cut`, |
| 496 | `awk` or `while read`. Lists show 20 entries unless `--limit` (`-L`) says |
| 497 | otherwise. |
| 498 | |
| 499 | ### Exit codes |
| 500 | |
| 501 | | Code | Meaning | |
| 502 | | --- | --- | |
| 503 | | `0` | It worked. | |
| 504 | | `1` | It failed: the API refused it, the network failed, checks or a run failed. | |
| 505 | | `2` | The command was used wrongly: an unknown flag, a missing argument, a JSON field that does not exist. | |
| 506 | | `4` | Signing in is needed, or the token was refused. | |
| 507 | | `8` | Checks are still running (`g1t pr checks` without `--watch`). | |
| 508 | |
| 509 | An error is one line on stderr, starting `g1t:`. When a token lacks a |
| 510 | [scope](/guides/authentication/#scopes) the call needs, the line names it. |
| 511 | |
| 512 | ### No questions when piped |
| 513 | |
| 514 | `g1t` asks for a missing title, opens an editor for a body, or offers a |
| 515 | choice only when stdin and stderr are both a terminal. Anywhere else, and |
| 516 | whenever `G1T_PROMPT_DISABLED` is set, a command missing something fails at |
| 517 | once with exit code `2` and names the flag that supplies it. |
| 518 | |
| 519 | ## Call any operation |
| 520 | |
| 521 | `g1t api` calls any operation of the [API](/reference/api/) by its name, |
| 522 | with your token, and fills the repository in from where you are: |
| 523 | |
| 524 | ```sh |
| 525 | g1t api list_issues -f state=closed --jq '.[].title' |
| 526 | g1t api create_label -f name=p1 -f color=d73a4a |
| 527 | g1t api get_workflow_run -f id=run_01kpx7b3c6d9e2f5g8h1j4k7mr |
| 528 | g1t api --list label # the operations about labels |
| 529 | ``` |
| 530 | |
| 531 | A path works too, with `{owner}`, `{name}` and `{workspace}` filled in: |
| 532 | |
| 533 | ```sh |
| 534 | g1t api /repos/{owner}/{name}/labels |
| 535 | g1t api user --jq .username |
| 536 | ``` |
| 537 | |
| 538 | `-f key=value` sends a string, `-F key=value` sends `true`, `false`, `null` |
| 539 | and numbers as JSON and `@file` as a file's contents, and `key[]=value` adds |
| 540 | to a list. Fields go in the query of a `GET` and in the JSON body otherwise. |
| 541 | `-X` sets the method, `-H` adds a header, and `--input file` sends a file as |
| 542 | the body. `--paginate` follows each next page, and with `--slurp` puts every |
| 543 | page's items in one array. A request the API refuses prints its error body |
| 544 | and exits `1`. |
| 545 | |
| 546 | In Git Bash on Windows, an argument starting with `/` is turned into a |
| 547 | Windows path before `g1t` sees it: leave the leading slash off |
| 548 | (`g1t api repos/{owner}/{name}`), or set `MSYS_NO_PATHCONV=1`. |
| 549 | |
| 550 | ## From agents and harnesses |
| 551 | |
| 552 | An agent with a shell, such as Claude Code, Codex or Cursor, can use `g1t` |
| 553 | the way you do. A command and its JSON cost an agent less of its context |
| 554 | than a set of tool definitions, and the agent finds what it needs with |
| 555 | `--help`. For clients without a shell, use the [MCP server](/reference/mcp/). |
| 556 | |
| 557 | 1. Install `g1t` where the agent runs, as [above](#install). |
| 558 | 2. Give it a token. Either sign in once with `g1t auth login` as the user |
| 559 | the agent runs as, or set `G1T_TOKEN` in its environment. Make a token |
| 560 | with only the [scopes](/guides/authentication/#scopes) it needs. |
| 561 | 3. Tell it `g1t` is there. A few lines in the project's `CLAUDE.md` or |
| 562 | `AGENTS.md` are enough: |
| 563 | |
| 564 | ```md |
| 565 | This repository is on g1t. Use the `g1t` CLI for issues, pull requests, |
| 566 | checks and runs; add `--json` to read results, and see `g1t <command> --help`. |
| 567 | |
| 568 | - Open a pull request: `g1t pr create --fill --issue <n>` |
| 569 | - Wait for checks: `g1t pr checks --watch --fail-fast` (exit 0 passed, 1 failed) |
| 570 | - See why a run failed: `g1t run logs --failed` |
| 571 | - Run a workflow by hand: `g1t workflow run <file> -f key=value` |
| 572 | - Anything else: `g1t api --list <word>`, then `g1t api <operation>` |
| 573 | ``` |
| 574 | |
| 575 | `g1t` never waits for input in an agent's shell, since its stdin is not a |
| 576 | terminal. Its JSON is compact and in a stable order, its lists are short |
| 577 | by default, and `g1t pr checks --watch --fail-fast` and `g1t run logs |
| 578 | --failed` give an agent the one thing it is waiting for, and no more. |
| 579 | |
| 580 | ## Aliases and completion |
| 581 | |
| 582 | An alias is a shortcut for a command you type often. `$1`, `$2`… take the |
| 583 | arguments after it, and the rest go on the end: |
| 584 | |
| 585 | ```sh |
| 586 | g1t alias set bugs 'issue list --label bug' |
| 587 | g1t alias set co 'pr checkout' |
| 588 | g1t alias set mine '!g1t pr list --author @me --json number,title' |
| 589 | g1t bugs --limit 5 |
| 590 | ``` |
| 591 | |
| 592 | An alias starting with `!` runs in `sh`. `g1t alias list` lists them, and |
| 593 | `g1t alias delete` removes one. |
| 594 | |
| 595 | `g1t completion <shell>` prints a completion script for `bash`, `zsh`, |
| 596 | `fish`, `powershell` or `elvish`: |
| 597 | |
| 598 | ```sh |
| 599 | g1t completion bash > ~/.local/share/bash-completion/completions/g1t |
| 600 | g1t completion zsh > "${fpath[1]}/_g1t" |
| 601 | g1t completion fish > ~/.config/fish/completions/g1t.fish |
| 602 | g1t completion powershell >> $PROFILE |
| 603 | ``` |
| 604 | |
| 605 | ## Settings and environment |
| 606 | |
| 607 | `g1t` keeps the hosts you are signed in to, their accounts and your aliases |
| 608 | in `config.json`, in `~/.config/g1t` (`%APPDATA%\g1t` on Windows; |
| 609 | `$XDG_CONFIG_HOME/g1t` when that is set). |
| 610 | |
| 611 | | Variable | | |
| 612 | | --- | --- | |
| 613 | | `G1T_TOKEN` | A token to use instead of the stored one. | |
| 614 | | `G1T_HOST` | The host to use when no repository names one. | |
| 615 | | `G1T_REPO` | The repository, as `[HOST/]OWNER/NAME`. | |
| 616 | | `G1T_CONFIG_DIR` | Where to keep `config.json`. | |
| 617 | | `G1T_KEYRING` | `off` keeps tokens out of the system's credential store. | |
| 618 | | `G1T_PROMPT_DISABLED` | Never ask anything. | |
| 619 | | `G1T_EDITOR`, `VISUAL`, `EDITOR` | The editor for bodies and summaries. | |
| 620 | | `G1T_BROWSER`, `BROWSER` | The browser `--web` and `g1t browse` open. | |
| 621 | | `NO_COLOR` | Plain output at a terminal too. | |
| 622 | | `G1T_DEBUG` | Print each request's method, address and status on stderr. | |