Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Validate Bash syntax
run: bash -n gitai

- name: Run ShellCheck
run: shellcheck -e SC1091 gitai

- name: Validate Homebrew formula Ruby syntax
run: ruby -c Formula/gitai.rb

- name: Verify executable bit and CLI version
run: |
test -x gitai
tmp="$(mktemp -d)"
git -C "$tmp" init
(cd "$tmp" && "$GITHUB_WORKSPACE/gitai" --version)
18 changes: 18 additions & 0 deletions Formula/gitai.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Gitai < Formula
desc "AI-assisted Conventional Commits with a terminal-native workflow"
homepage "https://github.com/jaavid/gitai"
head "https://github.com/jaavid/gitai.git", branch: "main"
license "MIT"

depends_on "gum"
depends_on "jq"

def install
bin.install "gitai"
end

test do
system "git", "init", testpath
assert_match "gitai 0.2.0", shell_output("#{bin}/gitai --version")
end
end
165 changes: 124 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,74 @@
# GitAI

**GitAI** is a small Bash script that generates commit messages using an AI model. The script inspects your staged changes and asks the configured API to suggest a commit title and description following the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) style.
GitAI is a small terminal-first assistant for generating Conventional Commit messages from staged Git changes, reviewing the result, committing it, and optionally pushing it to one or more remotes.

It stays close to normal Git instead of replacing your workflow. The UI uses [Gum](https://github.com/charmbracelet/gum) when available and falls back to plain terminal prompts when it is not.

## Features

- Works with your existing Git workflow.
- Supports multiple providers: AvalAI, OpenRouter, Cloudflare Workers AI, and Google AI Studio (Gemini API).
- Warns about unstaged changes before committing.
- Trims very large diffs to avoid sending excessively long requests.
- Interactive prompts let you review and accept the generated message.
- Generates Conventional Commit titles and descriptions from staged changes.
- Supports AvalAI, OpenRouter, Cloudflare Workers AI, and Google AI Studio (Gemini API).
- Supports provider fallback chains.
- Terminal UI for staging, reviewing, committing, and choosing a push target.
- Multi-remote aware: push to one remote or all configured remotes.
- Works well in Warp, iTerm2, Terminal.app, and other modern terminals without requiring terminal-specific APIs.
- Falls back to simple text prompts when Gum is unavailable or `GITAI_TUI=0`.
- Warns about changes outside the index and lets you keep the current staged set or stage everything.
- Trims very large diffs before sending them to an AI provider.
- User-wide and repository-specific configuration.

## Requirements

- `bash`
- [`curl`](https://curl.se/) for making HTTP requests
- [`jq`](https://stedolan.github.io/jq/) for parsing JSON
- `git`
- `curl`
- [`jq`](https://jqlang.github.io/jq/)
- [`gum`](https://github.com/charmbracelet/gum) for the richer terminal UI (optional outside Homebrew installs)

## Installation
## Install with Homebrew

Clone this repository and place the `gitai` script somewhere in your `PATH` or run it directly from the repository root:
This repository contains a Homebrew formula. Until a dedicated `homebrew-tap` repository exists, add this repository as a custom tap and install the HEAD formula:

```bash
# Clone the repository
git clone <repository url>
cd gitai
brew tap jaavid/gitai https://github.com/jaavid/gitai
brew install --HEAD jaavid/gitai/gitai
```

Upgrade later with:

# Optional: copy the script somewhere in your PATH
cp gitai /usr/local/bin/
```bash
brew update
brew upgrade --fetch-HEAD gitai
```

Homebrew installs `jq` and `gum` automatically.

### Manual install

```bash
git clone https://github.com/jaavid/gitai.git
cd gitai
install -m 755 gitai /usr/local/bin/gitai
```

## Configuration

GitAI needs API credentials. You can either use a shared key (`GITAI_API_KEY`) or provider-specific keys, and you can set them as environment variables or in a `.gitai` file next to the script.
GitAI reads configuration in this order, with later files overriding earlier values:

1. Legacy `.gitai` next to the executable, if present.
2. `~/.config/gitai/config` (or `$XDG_CONFIG_HOME/gitai/config`).
3. `.gitai` in the current repository root.

For API keys, prefer the user-wide config instead of committing credentials into a repository.

Example `.gitai` file:
Create it with:

```bash
mkdir -p ~/.config/gitai
$EDITOR ~/.config/gitai/config
```

Example:

```bash
export GITAI_PROVIDER="google,openrouter,cloudflare,avalapis"
Expand All @@ -46,7 +81,7 @@ export GITAI_CLOUDFLARE_ACCOUNT_ID="your-cloudflare-account-id"

### Provider options

Set `GITAI_PROVIDER` to one provider **or a comma-separated fallback chain**:
Set `GITAI_PROVIDER` to one provider or a comma-separated fallback chain:

- `avalapis` (default)
- `openrouter`
Expand All @@ -55,56 +90,104 @@ Set `GITAI_PROVIDER` to one provider **or a comma-separated fallback chain**:

Examples:

- `GITAI_PROVIDER="google,openrouter,cloudflare,avalapis"`
- `GITAI_PROVIDER="openrouter"`

Additional provider-specific variables:
```bash
export GITAI_PROVIDER="google,openrouter,cloudflare,avalapis"
```

- `openrouter`
- Optional: `GITAI_MODEL` (default `openai/gpt-4o-mini`)
- `cloudflare`
- Required unless `GITAI_API_BASE` is set: `GITAI_CLOUDFLARE_ACCOUNT_ID`
- Optional: `GITAI_MODEL` (default `@cf/meta/llama-3.3-70b-instruct-fp8-fast`)
- `google`
- Optional: `GITAI_MODEL` (default `gemini-2.0-flash`)
```bash
export GITAI_PROVIDER="openrouter"
```

Global optional variables:

- `GITAI_API_BASE`: Override endpoint URL (advanced use)
- `GITAI_MAX_DIFF_LENGTH`: Max diff chars sent to model (default `12000`)
- `GITAI_MODEL`: Shared default model override
- `GITAI_API_BASE`: override endpoint URL for advanced/custom setups.
- `GITAI_MAX_DIFF_LENGTH`: maximum staged diff characters sent to a provider (default: `12000`).
- `GITAI_MODEL`: shared model override.
- `GITAI_TUI=0`: disable Gum and use plain terminal prompts.

Per-provider API keys (recommended for fallback chains):
Per-provider API keys:

- `GITAI_AVALAPIS_API_KEY`
- `GITAI_OPENROUTER_API_KEY`
- `GITAI_CLOUDFLARE_API_KEY`
- `GITAI_GOOGLE_API_KEY`

Per-provider model overrides (optional):
Per-provider model overrides:

- `GITAI_AVALAPIS_MODEL`
- `GITAI_OPENROUTER_MODEL`
- `GITAI_CLOUDFLARE_MODEL`
- `GITAI_GOOGLE_MODEL`

Cloudflare additionally needs `GITAI_CLOUDFLARE_ACCOUNT_ID` unless `GITAI_API_BASE` is explicitly set.

## Usage

Stage your changes and run the script:
From any Git repository:

```bash
gitai
```

A typical flow is:

1. GitAI shows the repository, branch, and short status.
2. If needed, choose whether to stage all changes or keep only the current staged set.
3. GitAI sends only the staged diff to the configured AI provider chain.
4. Review the generated Conventional Commit message.
5. Confirm the commit.
6. Choose whether and where to push.

If the repository has multiple remotes, GitAI presents all of them together with an **All remotes** option. The current branch is pushed explicitly to each selected remote.

### Push options

```bash
# Commit, then ask where to push
gitai --push

# Commit and push to every configured remote
gitai --push-all

# Commit without offering to push
gitai --no-push
```

### Disable the richer TUI

```bash
gitai --no-tui
```

or:

```bash
git add file.txt
./gitai
export GITAI_TUI=0
```

GitAI will print git status, send your diff to the configured provider, and show the suggested commit message. You can then choose whether to commit and optionally push.
## Warp compatibility

GitAI deliberately uses normal shell input/output rather than a full-screen alternate-buffer UI. In Warp this means each run remains a normal command block, output stays searchable/copyable, and Git/GitAI subprocess output remains visible in the same block.

No Warp-specific configuration is required.

A complete example is available in [`examples/basic_usage.sh`](examples/basic_usage.sh).
## CLI reference

```text
gitai [options]

--push Push after committing; asks for a remote when necessary
--push-all Push to every configured remote
--no-push Never ask to push
--no-tui Use plain prompts instead of Gum
-v, --version
-h, --help
```

## Contributing

Contributions are welcome! Please open issues or pull requests on GitHub.
Issues and pull requests are welcome.

## License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
MIT — see [LICENSE](LICENSE).
Loading
Loading