AI-powered git commit tool. Uses OpenRouter to generate per-file commit messages from diffs, presented in a rich terminal UI.
Vibe coding with AI generates a high volume of changes — dozens of files touched per prompt. Manually writing commit messages for each file, staging, committing, and pushing becomes the bottleneck. gt removes that friction: it reads your diffs, generates per-file conventional commit messages, and lets you select, commit, and push everything from a single TUI. You stay in flow instead of context-switching to git housekeeping.
gtreadsgit statusand generates diffs for each changed file.- Diffs are sent to an AI model (via OpenRouter) to produce conventional commit messages (
type(scope): description). - A TUI displays all changed files with their AI-generated messages.
- You select files, review messages, and commit — each file gets its own atomic commit.
- Push to the current branch or create a new branch, all from inside the TUI.
| Dependency | Required | Notes |
|---|---|---|
| Go 1.21+ | Yes | For building from source |
| Git | Yes | Core dependency |
| OpenRouter API key | Yes | Sign up and grab a key from the dashboard |
GitHub CLI (gh) |
Optional | Required for push (p) and repo creation (gt init -r) |
brew update && brew install agentgino/tools/gtgit clone https://github.com/agentgino/gt.git
cd gt
make buildThis produces a gt binary in the project root. Move it somewhere on your $PATH:
sudo mv gt /usr/local/bin/go install github.com/himakarreddy/gt/cmd/gt@latestThis installs gt to $GOPATH/bin (or $HOME/go/bin if $GOPATH is not set). Make sure that directory is in your $PATH.
gt --versiongt setupThis prompts you for your OpenRouter API key and opens an interactive model picker. Use j/k or arrow keys to navigate, type to filter, and press enter to select.
Enter your OpenRouter API key: sk-or-v1-abc123...
Fetching models from OpenRouter...
Select a Model
> type to filter models...
▸ openai/gpt-4o
anthropic/claude-3.5-sonnet
google/gemini-pro
...
showing 142 models
j/k or ↑/↓ to move • enter to select • q to quit
Config is saved to ~/.gt.yaml with 0600 permissions (owner read/write only).
If you're starting a new project:
# Initialize git in an existing folder and create a GitHub repo with the folder name
gt init -r .
# Create a new folder, initialize git, and create a GitHub repo
gt init -r my-project
# Create under a GitHub organization
gt init -r my-org/my-project
# Create a public repo (default is private)
gt init -r my-project --public
# Use SSH URL instead of HTTPS
gt init -r my-project --sshIf you just want git init without creating a GitHub repo:
gt initcd /path/to/your/repo
# ... edit files ...
gt statusThis opens the TUI showing all changed files with AI-generated commit messages:
gt main → origin/main in sync │ model: openai/gpt-4o
────────────────────────────────────────────────────────
SEL STATUS FILE COMMIT MESSAGE
● modified internal/git/git.go feat(git): add HTTPS support for remote URLs
○ untracked internal/logger/logger.go feat(logger): implement structured slog logging
○ modified cmd/gt/main.go feat(cli): add version flag and verbose logging
────────────────────────────────────────────────────────
1 selected of 3 files
space select │ a all │ j/k move │ r regen │ c commit │ p push │ q quit
- Use
spaceto select/deselect files (orato toggle all) - Press
corenterto commit the selected files — each gets its own atomic commit - Press
pto push to remote
Configure your OpenRouter API key and select an AI model interactively.
gt setupWhat it does:
- Prompts for your API key (validated: must be 8+ characters)
- Fetches the full model list from OpenRouter
- Opens an interactive picker with search/filter
- Saves everything to
~/.gt.yaml
Initialize a git repository and optionally create a GitHub repository with remote.
gt init # just git init, no remote
gt init -r . # use current folder name as repo name
gt init -r my-project # create folder + repo + remote
gt init -r org/my-project # create under a GitHub organization
gt init -r my-project --public # public repo (default: private)
gt init -r my-project --ssh # use SSH URL (default: HTTPS)Behavior by flag:
| Command | Creates folder | git init | GitHub repo | Adds remote |
|---|---|---|---|---|
gt init |
No | Yes (cwd) | No | No |
gt init -r . |
No | Yes (cwd) | Yes (folder name) | Yes |
gt init -r name |
Yes (name/) |
Yes | Yes (name) |
Yes |
gt init -r org/name |
Yes (name/) |
Yes | Yes (org/name) |
Yes |
Flags:
| Flag | Short | Default | Description |
|---|---|---|---|
--repo |
-r |
(none) | GitHub repo name. Use . for current folder |
--public |
false |
Create a public repository | |
--ssh |
false |
Use SSH URL (git@github.com:...) instead of HTTPS |
Requirements: The gh CLI must be installed and authenticated (gh auth login) for any -r flag usage.
The main command. Shows changed files with AI-generated commit messages in an interactive TUI.
gt status # one-shot: show current changes
gt status -w # watch mode: auto-refreshes on file changesFlags:
| Flag | Short | Default | Description |
|---|---|---|---|
--watch |
-w |
false |
Watch filesystem for changes and auto-refresh |
Watch mode uses fsnotify to monitor the repo for file changes. When a file is saved, the TUI automatically refreshes the file list and regenerates commit messages only for files whose diffs actually changed (unchanged files keep their existing messages).
| Key | Action |
|---|---|
j / k / ↑ / ↓ |
Navigate files |
space |
Toggle file selection |
a |
Select all / deselect all |
c / enter |
Commit selected files (one commit per file) |
r |
Regenerate AI message for the current file |
p |
Push to remote (choose current branch or create new) |
g |
Generate .gitignore with AI (shown only when missing) |
q / ctrl+c |
Quit |
When you press c, each selected file gets its own atomic commit with the AI-generated message. After committing, the file list refreshes automatically — committed files disappear, remaining files stay.
When you press p, a chooser appears:
Push to remote
▸ Push to current branch (main)
Push to a new branch
enter select │ esc cancel
- Current branch — runs
git push(with-uif no upstream is set) - New branch — prompts for a branch name, creates it, and pushes with
-u
If no .gitignore exists in the repo root, a warning banner appears with a prompt to press g. This scans your project files, sends the file listing to the AI, and generates a language-appropriate .gitignore. The file list refreshes afterward to hide newly-ignored files.
Switch the AI model after initial setup.
gt modelsOpens the same interactive model picker as gt setup, but only changes the model (keeps your API key).
Print the current version.
gt --version
# gt version v1.2.0Version is injected at build time. When building with make build, it uses git describe --tags --always --dirty.
These flags work with any command:
| Flag | Short | Default | Description |
|---|---|---|---|
--version |
Print version and exit | ||
--verbose |
-v |
false |
Enable debug logging to stderr |
Verbose mode outputs structured logs (via log/slog) to stderr, useful for debugging API calls, git operations, and watcher events.
gt -v statusConfig is stored in ~/.gt.yaml with 0600 permissions:
api_key: "sk-or-v1-..."
model: "openai/gpt-4o"
remote_protocol: "https" # "https" or "ssh" — default for new remotes
max_concurrent: 5 # parallel AI requests (1-20)
debounce_ms: 500 # watcher debounce interval in ms| Key | Type | Default | Description |
|---|---|---|---|
api_key |
string | (none) | Your OpenRouter API key |
model |
string | (none) | AI model ID (e.g.openai/gpt-4o) |
remote_protocol |
string | "https" |
Default protocol for new remotes |
max_concurrent |
int | 5 |
Max parallel AI requests to OpenRouter |
debounce_ms |
int | 500 |
How long to wait after a file change before refreshing (ms) |
max_concurrent controls how many commit messages are generated in parallel. Higher values are faster but may trigger OpenRouter rate limits. Lower values are safer for free-tier keys.
debounce_ms prevents rapid-fire refreshes when editors save multiple files at once (e.g. auto-format on save). The watcher waits this long after the last file change before refreshing.
mkdir my-app && cd my-app
# Initialize git + create private GitHub repo + add HTTPS remote
gt init -r .
# Configure AI
gt setup
# Write some code...
echo 'package main' > main.go
# Review AI-generated messages, select, commit, push
gt statuscd ~/projects/my-app
# See all changes with AI messages
gt status
# In the TUI:
# 1. Press 'a' to select all
# 2. Review messages, press 'r' on any file to regenerate
# 3. Press 'c' to commit all
# 4. Press 'p' to pushgt status -wLeave this running in a terminal pane. Every time you save a file, the TUI refreshes and generates a new commit message. Select and commit when ready.
gt generates conventional commit messages:
type(scope): description
| Type | When |
|---|---|
feat |
New feature or functionality |
fix |
Bug fix |
refactor |
Code restructuring without behavior change |
docs |
Documentation changes |
style |
Formatting, whitespace, missing semicolons |
test |
Adding or updating tests |
chore |
Maintenance, dependencies, config |
perf |
Performance improvement |
ci |
CI/CD changes |
build |
Build system changes |
The AI reads the actual diff line-by-line and generates specific messages describing what changed — not just the filename.
gt uses OpenRouter as the AI provider. OpenRouter routes to 200+ models (OpenAI, Anthropic, Google, Meta, etc.) with a single API key.
- Rate limiting: If you hit a 429,
gtretries automatically with exponential backoff (up to 3 retries) - Server errors: 502/503 errors are also retried automatically
- Timeouts: Each AI request has a 2-minute timeout
- Diff truncation: Large diffs are truncated to 4000 characters to stay within token limits
Reduce max_concurrent in config if you're hitting rate limits frequently.
make build # build binary with version from git tags
make install # install to $GOPATH/binmake test # run all tests
make test-race # run with race detector
make test-cover # generate coverage report (coverage.html)make fmt # go fmt
make vet # go vet
make lint # fmt + vet + golangci-lintgo build -ldflags "-X main.Version=v2.0.0" -o gt ./cmd/gtgt/
├── cmd/gt/main.go # CLI entry point (cobra commands)
├── internal/
│ ├── ai/
│ │ ├── client.go # OpenRouter API client with retry
│ │ └── client_test.go # HTTP mock tests
│ ├── config/
│ │ ├── config.go # YAML config with defaults
│ │ └── config_test.go # Load/save/validation tests
│ ├── git/
│ │ ├── git.go # Git operations (status, diff, commit, push)
│ │ └── git_test.go # Status parsing, branch, remote tests
│ ├── logger/
│ │ └── logger.go # slog-based structured logging
│ ├── tui/
│ │ ├── status.go # Main status TUI
│ │ └── modelselect.go # Model selection TUI
│ └── watcher/
│ ├── watcher.go # Filesystem watcher with debounce
│ └── watcher_test.go # Watch/debounce/filter tests
├── go.mod
├── go.sum
├── Makefile
├── TODO.md
└── README.md
Run gt init in your project directory first, or make sure you're inside a git repo.
You need to configure an API key and model before using gt status. Run gt setup.
The push feature and gt init -r require the gh CLI:
# Install (macOS)
brew install gh
# Authenticate
gh auth logingt defaults to HTTPS remotes, which work with gh CLI auth. If your existing remote uses SSH and you don't have SSH keys configured:
# Check your remote URL
git remote get-url origin
# Switch to HTTPS
git remote set-url origin https://github.com/user/repo.gitOr configure SSH keys: https://docs.github.com/en/authentication/connecting-to-github-with-ssh
Reduce parallel requests in ~/.gt.yaml:
max_concurrent: 2gt -v statusThis prints structured logs to stderr showing API calls, git operations, and timing.
See LICENSE for details.