Skip to content

Get started

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.

g1t is the command line for g1t. It does the work you would otherwise do on the site: open and review pull requests, wait on checks, read a failing run’s logs, set secrets, read a project’s logs, and call any operation of the API. It is one file with nothing to install alongside it, and it is built to be run by agents as much as by people: every command can print JSON, nothing waits for input unless a person is at the terminal, and exit codes say what happened.

g1t issue list --label bug
g1t pr create --fill
g1t pr checks --watch --fail-fast
g1t run logs --failed

Every command and flag is listed in the command reference.

On Linux or macOS:

curl -fsSL https://g1t.sh/install | sh

On Windows, in PowerShell:

irm https://g1t.sh/install.ps1 | iex

The script picks the build for your system, checks it against the release’s SHA256SUMS, and puts g1t in ~/.local/bin (Windows: %LOCALAPPDATA%\g1t\bin, which it adds to your PATH). Set G1T_INSTALL_DIR to put it elsewhere, or G1T_VERSION to install a version other than the latest. Run it again to update.

Each release is a single file per platform, at https://g1t.sh/downloads/cli/latest/:

Platform File
Linux, x64 g1t-linux-x64
Linux, ARM g1t-linux-arm64
macOS, Apple silicon g1t-macos-arm64
macOS, Intel g1t-macos-x64
Windows, x64 g1t-windows-x64.exe
curl -fsSLo g1t https://g1t.sh/downloads/cli/latest/g1t-linux-x64
chmod +x g1t && mv g1t ~/.local/bin/

Check a download against https://g1t.sh/downloads/cli/latest/SHA256SUMS. latest.json beside it names the version and each file’s SHA-256, and latest.json.sig is its signature. A given version’s files are at /downloads/cli/<version>/ and never change.

To build it from source, with Rust:

git clone https://g1t.sh/flagon-io/g1t
cargo install --path g1t/crates/g1t

g1t --version prints the version you have.

g1t auth login

g1t shows a one-time code and opens your browser at g1t.sh/device. Sign in there if you are not already, check the code matches, and approve. The command finishes on its own once you have. Where there is no browser (a server, a container, a remote shell), it prints the link instead: open it on any device.

To use an access token you already have, pipe it in:

g1t auth login --with-token < token.txt

The token is kept in your system’s credential store: the Keychain on macOS, Credential Manager on Windows, the Secret Service on Linux. Where there is none, as on most servers, it goes in the config file, readable only by you; --insecure-storage puts it there on purpose.

Command What it does
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.
g1t auth token Prints the token in use, for another program.
g1t auth logout Forgets an account’s token.
g1t auth switch Makes another signed-in account on the same host the active one.

When G1T_TOKEN is set, every command uses it instead of a stored token. This is how to give g1t a token in containers, in agents’ sandboxes, and in workflows, where the job’s own token is secrets.G1T_TOKEN:

- run: g1t pr comment ${{ github.event.pull_request.number }} -b "Preview is up."
env:
G1T_TOKEN: ${{ secrets.G1T_TOKEN }}

g1t works with any g1t, not only g1t.sh. Sign in to yours with its address:

g1t auth login --hostname git.example.com

g1t asks it where its API is (its /.well-known/g1t.json), and remembers. After that, commands in a clone of one of its repositories talk to it on their own. Elsewhere, name it with --hostname or G1T_HOST; the first host you sign in to is the default. You can be signed in to several hosts, and as several accounts on each.

g1t auth setup-git

This makes g1t git’s credential helper for each host you are signed in to, so git push, git fetch and git clone over HTTPS use the same token, with nothing more to type. It changes your global git config only for those hosts’ addresses (credential.https://g1t.sh.helper). g1t auth login --git does both at once. To see the config lines without changing anything, add --dry-run.

g1t push, which sends container images to g1t’s registry, uses the same signed-in token.

Commands about a repository work on the one the current directory is a clone of, found from its git remotes: upstream if it is on g1t, then origin, then the first one that is. In a pull request’s own working copy, they work on the repository the pull request is for.

Anywhere else, or to choose another, pass --repo (-R), or set G1T_REPO:

g1t issue list -R acme/web
g1t pr view 14 -R git.example.com/acme/web
g1t issue list # open issues, newest first
g1t issue list --label bug --assignee @me
g1t issue view 12 --comments
g1t issue create -t "Greeting should name the caller" -b "Take a name from the first argument."
g1t issue comment 12 -b "Fixed in #14."
g1t issue edit 12 --add-label p1 --add-assignee @me
g1t issue close 12 --reason not_planned

@me is you. At a terminal, g1t issue create without --title asks for one and opens your editor for the body.

From a branch with your commits on it:

git switch -c greet-by-name
# ...commit...
g1t pr create --fill --issue 12

g1t pr create pushes the branch, then opens the pull request into the default branch (--base for another). --fill takes the title and body from the branch’s commits; --issue says which issue it is for; --draft opens it as a draft.

To start a pull request for an issue without a branch of your own, as g1t’s agents do, run it with --issue from the default branch. g1t opens a draft with a working copy of its own and prints the copy’s git remote. Push your commits there, then mark it ready with a summary of what changed and why:

g1t pr create --issue 12
git push https://g1t.sh/pulls/pr_….git HEAD:main
g1t pr ready --summary "Reads a name from the first argument."

Then, for any pull request:

g1t pr list
g1t pr view 14 # the current branch's when left out
g1t pr diff 14
g1t pr checkout 14 # check its head out locally
g1t pr checks 14 --watch
g1t pr review 14 --approve -b "Reads well."
g1t pr review 14 --request-changes -b "Trim the name first."
g1t pr merge 14 --delete-branch

g1t pr merge merges the way the repository is set to, once required checks pass and rules allow; --admin merges past them, with the Admin role.

g1t pr checks lists a pull request’s checks: g1t Actions jobs, check runs and commit statuses. With --watch it waits until they have all finished, redrawing at a terminal and printing a line per change when piped. --fail-fast stops at the first failure instead of waiting for the rest. It exits 0 when every check passed, 1 when one failed, and, without --watch, 8 while any are still running.

g1t run list --branch main
g1t run view # the current branch's latest run
g1t run watch run_01kpx7b3c6d9e2f5g8h1j4k7mr
g1t run logs --failed
g1t run rerun --failed

A run is named by its id (run_…), its number, or its address; left out, it is the current branch’s latest. g1t run logs --failed prints only the steps that failed, each with its last 60 lines (-n for more or fewer): what you need to see why, without the rest of the log. g1t run watch exits 1 if the run fails.

g1t workflow works with the workflows in .g1t/workflows, as the repository’s Actions page does.

g1t workflow list # those turned on; --all for every one
g1t workflow view ci.yml # its triggers, inputs and latest runs
g1t workflow view release.yml --yaml --ref v1.4.0
g1t workflow run release.yml -f channel=stable
g1t workflow disable Nightly
g1t workflow enable nightly.yml

A workflow is named by its file name (ci.yml), its id (wfl_…) or its name (CI, in any case). When more than one has that name, name it by its file. Left out at a terminal, g1t asks which; in a script it is an error that names what to pass.

g1t workflow run runs a workflow that has on: workflow_dispatch, on the default branch or the branch or tag --ref names, and prints its run’s address once the run is there, so g1t run watch can follow it. Give its inputs with -f key=value (or -F key=@file to read a value from a file), or as one JSON object on stdin with --json:

echo '{"channel":"stable","dry_run":true}' | g1t workflow run release.yml --json

At a terminal with no inputs given, g1t asks for each, offering its default. Only the inputs the workflow declares are taken, as on the Actions page. g1t workflow view --yaml prints the workflow’s file as it is on the default branch, or on --ref. Turning a workflow off keeps its file: nothing starts it until it is turned on again, and a workflow the workspace requires stays on.

g1t deploy list --env production
g1t deploy view dep_01kq8m3t5v7x9z1b3d5f7h9k2m
g1t logs --since 1h --level error,fatal
g1t logs -q '"payment failed"' --follow
g1t logs --errors --state open
g1t secret list
echo "$NPM_TOKEN" | g1t secret set NPM_TOKEN
g1t secret set STRIPE_KEY --env production < stripe-key.txt
g1t secret set NPM_TOKEN --brokered-host registry.npmjs.org < npm-token.txt
g1t secret delete STRIPE_KEY --env preview
g1t secret list --workspace acme

g1t logs reads the observability data of the current repository’s project, or of --project WORKSPACE/SLUG. A secret’s value is read from stdin, so it stays out of your shell’s history; at a terminal with nothing piped, g1t asks for it without echoing. Values are never printed. --brokered-host makes it a brokered secret.

g1t status

Your open pull requests and their checks, reviews asked of you, what is assigned to you, and failing checks, across every repository you can see. Inside a working copy it also lists your active sessions and claims in that repository.

When several people and agents work in one repository, g1t session and g1t work say who is on what, so nobody starts work that is already under way and everyone hears what changes under them. Claims are advisory: a claim never stops anyone, it tells them.

A session is one run of an agent’s harness, such as one Claude Code session. Starting one remembers it for the working copy, and the commands after it use it:

g1t session start --harness claude-code --issue 12
g1t session log "Split the parser before touching the lexer."
g1t session attach --pull 14 --head-commit "$(git rev-parse HEAD)"
g1t session heartbeat
g1t session end --reason done
Command What it does
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).
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.
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.
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.
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.
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.
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.
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.

The id is kept in .git/g1t/session, in the working copy’s own git directory, so each worktree has its own. G1T_SESSION overrides it, for a harness that runs several sessions in one working copy.

g1t work context 12 # everything about #12's work
g1t work claim 12 --note "Taking the parser" --ttl 1h
g1t work claim --title "Preview builds time out" --body "Over 1 GB, the build stops at 10 minutes."
g1t work release 12 --reason done
g1t work handoff 12 --to ana --note "Parser done; lexer tests still fail."
g1t work list # active claims and sessions here

g1t work context is the one call to make before starting: the issue and its definition of done, who has claimed it, its sessions, its pull requests with their checks, overlaps and place in the merge queue, what it waits on and what waits on it, its decisions, its last integration failure and its recent events.

g1t work claim says you are working on an issue. It lasts 30 minutes unless --ttl says otherwise (at most 4h), and a heartbeat of the session it was made in renews it. It is made in the current session, if there is one. If others have claimed the issue too, or it waits on issues that are not done, the answer says so. g1t work handoff ends your claim and asks --to someone, or anyone without it, to take the issue over, with a --note saying where it stands. Claims, releases and hand-offs are the current session’s, so two sessions of yours (sibling subagents) each hold their own.

For work that has no issue yet, g1t work claim --title "…" (with --body for its description) opens the issue and claims it in one step, and attaches the current session to it; it prints the new issue’s number. Use it once the work is a change others should know about, after looking for an issue that already covers it; questions, exploration and trivial fixes need none. A number and --title together are refused.

g1t work dispatch 12 # on the workspace's Anthropic account
g1t work dispatch 12 --mode plan --instruction "Keep the old flag"
g1t work dispatch --title "Add a healthcheck" --handoff # open the issue; print a claude command

g1t work dispatch starts work on an issue in a session on your own Claude: with the workspace’s Anthropic connection, a Claude Managed Agents session on that account (it prints the session’s page on g1t); without one, or with --handoff, the claude command line to run in your working copy with g1t’s Claude Code plugin. --managed fails rather than hand off. --mode is plan, implement or review. See Start a session on your Anthropic account.

g1t work block 12 --by 9 --by 10 # #12 waits on #9 and #10
g1t work unblock 12 --by 9

These change the issue’s blocked_by through update_issue. An issue cannot wait on itself, and g1t refuses a cycle.

g1t work events prints the repository’s recent events, oldest first. With --follow it keeps printing them as they happen, without a webhook or a public address, until you stop it with Ctrl-C:

g1t work events --follow --issue 12
g1t work events --follow --type integration.failed --type overlap.detected --json
Flag
--type, -t Only events of this type, such as work.claimed; repeat for more.
--issue, -i Only events about this issue or pull request; repeat for more.
--since, -s Only events since then: 15m, 2h, 1d, or an RFC 3339 time.
--after Start after this event id, to resume where an earlier follow stopped.
--limit, -L How many past events to show first; 20 by default.

Each event is one line: its time, type, issue or pull request, a summary and its id. With --json, each is one compact JSON object on a line of its own, so a program can read them as they come. Following asks list_events with after and wait, so the server holds each request until something happens; when a call fails, g1t waits (1 second, then longer, up to 30) and resumes from the last event it printed. A refused token stops it with exit code 4.

g1t why src/parser.rs:120
g1t why src/parser.rs --ref main

g1t why follows a line to the commit that last changed it, the pull request that merged that commit, the issue the pull request was for, and the decisions and sessions recorded on them. A path is read from where you are in the working copy.

These commands are made to be run by a harness’s hooks in the background: they never ask anything, they fail at once with exit code 4 when there is no token, and they give up on a call after 15 seconds. Against a g1t server older than the CLI, a command it cannot do yet fails saying so.

Every command takes --json. Alone, it prints every field the API returns; with a comma-separated list, only those (g1t workflow run is the one exception: there, --json alone reads the inputs from stdin):

g1t pr list --json number,title,check_status
[{"check_status":"passed","number":14,"title":"Greeting should name the caller"}]

The fields are the API’s own, named as in the API reference and always snake_case. A field that does not exist is an error that lists the ones that do. Piped, JSON is one compact line with its keys in a fixed order, so the same input gives the same output; at a terminal it is indented.

--jq runs a jq expression over the JSON, with nothing else to install. Strings come out bare, everything else as JSON:

g1t pr list --jq '.[] | select(.check_status == "failed") | .number'
g1t run list --jq '.[] | [.id, .conclusion] | @tsv'

Without --json, output piped to another program is one record per line, fields separated by tabs, with no header and no color, ready for cut, awk or while read. Lists show 20 entries unless --limit (-L) says otherwise.

Code Meaning
0 It worked.
1 It failed: the API refused it, the network failed, checks or a run failed.
2 The command was used wrongly: an unknown flag, a missing argument, a JSON field that does not exist.
4 Signing in is needed, or the token was refused.
8 Checks are still running (g1t pr checks without --watch).

An error is one line on stderr, starting g1t:. When a token lacks a scope the call needs, the line names it.

g1t asks for a missing title, opens an editor for a body, or offers a choice only when stdin and stderr are both a terminal. Anywhere else, and whenever G1T_PROMPT_DISABLED is set, a command missing something fails at once with exit code 2 and names the flag that supplies it.

g1t api calls any operation of the API by its name, with your token, and fills the repository in from where you are:

g1t api list_issues -f state=closed --jq '.[].title'
g1t api create_label -f name=p1 -f color=d73a4a
g1t api get_workflow_run -f id=run_01kpx7b3c6d9e2f5g8h1j4k7mr
g1t api --list label # the operations about labels

A path works too, with {owner}, {name} and {workspace} filled in:

g1t api /repos/{owner}/{name}/labels
g1t api user --jq .username

-f key=value sends a string, -F key=value sends true, false, null and numbers as JSON and @file as a file’s contents, and key[]=value adds to a list. Fields go in the query of a GET and in the JSON body otherwise. -X sets the method, -H adds a header, and --input file sends a file as the body. --paginate follows each next page, and with --slurp puts every page’s items in one array. A request the API refuses prints its error body and exits 1.

In Git Bash on Windows, an argument starting with / is turned into a Windows path before g1t sees it: leave the leading slash off (g1t api repos/{owner}/{name}), or set MSYS_NO_PATHCONV=1.

An agent with a shell, such as Claude Code, Codex or Cursor, can use g1t the way you do. A command and its JSON cost an agent less of its context than a set of tool definitions, and the agent finds what it needs with --help. For clients without a shell, use the MCP server.

  1. Install g1t where the agent runs, as above.
  2. Give it a token. Either sign in once with g1t auth login as the user the agent runs as, or set G1T_TOKEN in its environment. Make a token with only the scopes it needs.
  3. Tell it g1t is there. A few lines in the project’s CLAUDE.md or AGENTS.md are enough:
This repository is on g1t. Use the `g1t` CLI for issues, pull requests,
checks and runs; add `--json` to read results, and see `g1t <command> --help`.
- Open a pull request: `g1t pr create --fill --issue <n>`
- Wait for checks: `g1t pr checks --watch --fail-fast` (exit 0 passed, 1 failed)
- See why a run failed: `g1t run logs --failed`
- Run a workflow by hand: `g1t workflow run <file> -f key=value`
- Anything else: `g1t api --list <word>`, then `g1t api <operation>`

g1t never waits for input in an agent’s shell, since its stdin is not a terminal. Its JSON is compact and in a stable order, its lists are short by default, and g1t pr checks --watch --fail-fast and g1t run logs --failed give an agent the one thing it is waiting for, and no more.

An alias is a shortcut for a command you type often. $1, $2… take the arguments after it, and the rest go on the end:

g1t alias set bugs 'issue list --label bug'
g1t alias set co 'pr checkout'
g1t alias set mine '!g1t pr list --author @me --json number,title'
g1t bugs --limit 5

An alias starting with ! runs in sh. g1t alias list lists them, and g1t alias delete removes one.

g1t completion <shell> prints a completion script for bash, zsh, fish, powershell or elvish:

g1t completion bash > ~/.local/share/bash-completion/completions/g1t
g1t completion zsh > "${fpath[1]}/_g1t"
g1t completion fish > ~/.config/fish/completions/g1t.fish
g1t completion powershell >> $PROFILE

g1t keeps the hosts you are signed in to, their accounts and your aliases in config.json, in ~/.config/g1t (%APPDATA%\g1t on Windows; $XDG_CONFIG_HOME/g1t when that is set).

Variable
G1T_TOKEN A token to use instead of the stored one.
G1T_HOST The host to use when no repository names one.
G1T_REPO The repository, as [HOST/]OWNER/NAME.
G1T_CONFIG_DIR Where to keep config.json.
G1T_KEYRING off keeps tokens out of the system’s credential store.
G1T_PROMPT_DISABLED Never ask anything.
G1T_EDITOR, VISUAL, EDITOR The editor for bodies and summaries.
G1T_BROWSER, BROWSER The browser --web and g1t browse open.
NO_COLOR Plain output at a terminal too.
G1T_DEBUG Print each request’s method, address and status on stderr.