Metadata-Version: 2.4
Name: gitaiflow
Version: 1.0.1
Summary: Provider-agnostic AI change-summary generator for git repos -- works with Gemini, OpenAI, or local Ollama models.
Author: CodeFleet Labs
License-Expression: MIT
Project-URL: Homepage, https://gitlab.com/codefleet-labs/gitaiflow
Project-URL: Repository, https://gitlab.com/codefleet-labs/gitaiflow
Project-URL: Issues, https://gitlab.com/codefleet-labs/gitaiflow/-/issues
Keywords: gitaiflow,ai,git,diff,engineering,django,ollama,llm,pr-summary,developer-tools,git-analysis
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Version Control :: Git
Classifier: Topic :: Utilities
Classifier: Environment :: Console
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: ruff>=0.5.0; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: build>=1.2.1; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Dynamic: license-file

# gitaiflow

[![Python](https://img.shields.io/pypi/pyversions/gitaiflow)](https://pypi.org/project/gitaiflow/)
[![PyPI](https://img.shields.io/pypi/v/gitaiflow)](https://pypi.org/project/gitaiflow/)
[![Downloads](https://static.pepy.tech/badge/gitaiflow)](https://pepy.tech/project/gitaiflow)
[![Build](https://github.com/codefleetx/gitaiflow/actions/workflows/tests.yml/badge.svg)](https://github.com/codefleetx/gitaiflow/actions/workflows/tests.yml)
[![License](https://img.shields.io/github/license/codefleetx/gitaiflow)](LICENSE)
[![GitHub Release](https://img.shields.io/github/v/release/codefleetx/gitaiflow)](https://github.com/codefleetx/gitaiflow/releases)
[![GitHub Stars](https://img.shields.io/github/stars/codefleetx/gitaiflow?style=social)](https://github.com/codefleetx/gitaiflow/stargazers)

<!--
  Coverage badge intentionally omitted: it needs pytest-cov generating
  a coverage report in CI plus a registered project on codecov.io.
  Neither exists yet -- add both, then restore:
  [![Coverage](https://img.shields.io/codecov/c/github/codefleetx/gitaiflow)](https://codecov.io/gh/codefleetx/gitaiflow)
-->
<u>Maintained by: <img src="./static/assets/logo/icon.png" height="16" alt="DjangoPlay icon"> <a href="https://djangoplay.org"><img src="./static/assets/logo/name.png" height="12" alt="DjangoPlay"></a></u>

---

Generate an AI change summary from your git diff -- as a single,
timestamped JSON file that's ready to use as a commit title/body,
pipe into a commit-msg hook, or feed to another tool/agent.

Works with **any** AI provider: a free Google Gemini API key, a fully
local Ollama model, or any OpenAI-compatible endpoint (OpenAI, Groq,
DeepSeek, OpenRouter, vLLM, LM Studio, ...). One config, one output
format, no vendor lock-in.

```bash
$ gitaiflow --path mailer/ --print-commit

mailer: add retry backoff for failed sends

- Added exponential backoff retry logic in retry.py
- tasks.py now retries send_mail up to 3 times on failure
- No changes to public function signatures
```

## Install

```bash
pip install gitaiflow
```

## Configure an AI provider (required)

gitaiflow needs an AI model configured -- it will not run without
one.

### OpenRouter (recommended)

gitaiflow can use OpenRouter's free model router by default, or any
specific free or paid model available through your OpenRouter account.

Create an OpenRouter account and generate an API key:

https://openrouter.ai/

Then add your key to `.gitaiflow.env` in your repository root:

```bash
AI_PROVIDER=custom
AI_BASE_URL=https://openrouter.ai/api/v1
AI_API_KEY=<your-openrouter-api-key>
AI_MODEL=openrouter/free

AI_TEMPERATURE=0.2
AI_MAX_TOKENS=10000
AI_REQUEST_TIMEOUT=60
```

Keep your API key private. Do not commit `.gitaiflow.env` or your API
key to source control.

`openrouter/free` automatically selects an available free model, so you
do not need to maintain a model name manually.

### Use a paid OpenRouter model

If you have access to paid models through OpenRouter, use your own
OpenRouter API key and specify the model you want:

```bash
AI_API_KEY=<your-openrouter-api-key>
AI_MODEL=<openrouter-model-id>
```

Usage is charged according to your OpenRouter account and selected
model. gitaiflow does not provide or manage the model subscription.

### Finding a free OpenRouter model

If you're using OpenRouter and want to pick a specific model rather
than the `openrouter/free` auto-router, list what's currently
available instead of hand-writing `curl`/`jq`:

```bash
gitaiflow --list-models --free-only
```

```text
ID                                    CONTEXT    FREE
nvidia/nemotron-3.5-lightning:free    128000     yes
meta-llama/llama-3.3-70b:free         131000     yes
...
```

Drop the `--free-only` flag to see paid models too, or add `--json`
for the raw OpenRouter response (all metadata fields, not just the
table columns shown above). This queries OpenRouter's live catalog on
every call -- gitaiflow doesn't maintain its own model list, so newly
added or removed models show up automatically.

`--list-models` works independent of your configured `AI_PROVIDER` --
it always targets OpenRouter regardless of what you have `AI_MODEL`
set to today, and doesn't require an API key (OpenRouter's catalog
endpoint is public). It only looks up models; it never changes your
configured `AI_MODEL`.

### Other providers

**1. Gemini (free tier, cloud)**

```bash
export AI_PROVIDER=gemini
export AI_API_KEY=<your-key>          # https://aistudio.google.com/apikey
```

**2. Ollama (local, no API key, no cost)**

```bash
export AI_PROVIDER=ollama
export AI_MODEL=llama3.2:3b           # must match `ollama list` exactly
```

**3. Any OpenAI-compatible provider (OpenAI, Groq, self-hosted, ...)**

```bash
export AI_PROVIDER=custom
export AI_BASE_URL=<endpoint>
export AI_API_KEY=<key>
export AI_MODEL=<model>
```

Any of these can also live in a `.gitaiflow.env` file in your repo
root instead of real environment variables (same `KEY=value` format).
If nothing is configured, `gitaiflow` fails fast with these same
instructions rather than partway through a run.

Full config reference:

| Variable | Default | Notes |
|---|---|---|
| `AI_PROVIDER` | `gemini` | `gemini` \| `ollama` \| `openai` \| `custom` |
| `AI_BASE_URL` | provider default | override for any provider |
| `AI_API_KEY` | (none) | required for gemini/openai/custom; not needed for ollama |
| `AI_MODEL` | provider default | e.g. `gemini-flash-lite-latest`, `llama3.2:3b`, `gpt-4.1-mini` |
| `AI_TEMPERATURE` | `0.2` | |
| `AI_MAX_TOKENS` | `10000` | |
| `AI_REQUEST_TIMEOUT` | `60` | seconds |

## Usage

```bash
gitaiflow --path mailer/                        # summarize a directory
gitaiflow --path users/views/logout.py           # summarize a single file
gitaiflow --path . --skip migrations tests       # skip paths
gitaiflow --path . --remote upstream --base-branch develop
gitaiflow --path . -o artifacts/                 # custom output root
gitaiflow --path . --markdown                    # also write a .md view
gitaiflow --path . --print-commit                # print title+body to stdout
```

`--print-commit` is meant to be piped straight into git:

```bash
gitaiflow --path . --print-commit > /tmp/msg.txt && git commit -F /tmp/msg.txt
```

## Output

Every run writes one JSON file to `change-summary/json/<target>-<timestamp>.json`:

```json
{
  "generated_at": "2026-08-19T14:32:07+05:30",
  "target": "mailer",
  "target_type": "directory",
  "repository": "paystream",
  "branch": "feature/mailer-retry",
  "base": "origin/main",
  "author": { "name": "Chandrashekhar Bhosale", "email": "shekhar@djangoplay.org" },
  "change_window": {
    "first_change_at": "2026-08-18 09:12:03",
    "last_change_at": "2026-08-19 14:30:11"
  },
  "files_changed": [
    { "path": "mailer/tasks.py", "status": "modified" },
    { "path": "mailer/retry.py", "status": "added" }
  ],
  "model": { "provider": "gemini", "name": "gemini-flash-lite-latest" },
  "commit": {
    "title": "mailer: add retry backoff for failed sends",
    "body": "- Added exponential backoff retry logic in retry.py\n- tasks.py now retries send_mail up to 3 times on failure\n- No changes to public function signatures"
  },
  "summary": "(same content as commit.body)"
}
```

`author`, `branch`, `base`, `change_window`, and `files_changed` come
straight from git -- never from the model -- so they're accurate even
if the AI call fails or hallucinates. `commit.title` / `commit.body`
are the only model-generated fields, and they're the ones designed to
be commit-ready as-is.

`--markdown` renders a second, human-facing view from the same JSON
into `change-summary/markdown/` -- the JSON is always the source of
truth.

## Local usage log

Every run appends one line to `~/.gitaiflow/usage.jsonl` -- timestamp,
repo name, target type, model used, estimated token counts, duration,
success. **This file never leaves your machine.** It exists so you
can see your own usage and, optionally, set soft daily limits:

```bash
export GITAIFLOW_MAX_RUNS_PER_DAY=20
export GITAIFLOW_MAX_TOKENS_PER_DAY=50000
```

When set, gitaiflow prints a warning once you've crossed the
threshold for the day. This is a courtesy guardrail against
accidentally running up a cloud-model bill, not enforcement -- it's a
local file, and any user can clear it.

## Repository layout

`telemetry_server/` lives inside this same repo, at the root, next to
the `gitaiflow/` package.

```text
gitaiflow/                    (repo root)
├── gitaiflow/                <- the PyPI package (this is what `pip install gitaiflow` installs)
│   ├── config/
│   ├── services/
│   ├── prompts/
│   └── generate_summary.py   <- CLI entry point
├── telemetry_server/         <- standalone Flask receiver, deployed separately to
│   ├── app.py                   host server, for example, `app.djangoplay.org`
│   ├── requirements.txt
├── .gitlab-ci.yml
├── .gitlab/ci/
│   ├── pypi-release.yml      <- test -> build -> version-check -> publish (manual, main only)
│   ├── github-mirror.yml     <- mirrors main to GitHub on every push
│   └── deploy-telemetry.yml  <- deploys telemetry_server/ to production (manual, main only)
├── .github/workflows/gitlab-mirror.yml
├── pyproject.toml
└── README.md                 <- this file
```

Two independent things ship from this one repo: the `gitaiflow` PyPI
package (what end users `pip install`), and the telemetry receiver
(a small internal service you run, not part of the package). They
share a repo and a CI pipeline but nothing else at runtime.

## Telemetry (opt-in, off by default)

gitaiflow does **not** phone home by default. If you explicitly set:

```bash
export GITAIFLOW_TELEMETRY=true
```

then each run sends exactly below details, to configured telemetry receiver 
`https://app.djangoplay.org/gitaiflow-telemetry/v1/events` (the
maintainer's self-hosted receiver), and nothing else:

| Field | Example |
|---|---|
| `install_id` | random UUID, generated once locally |
| `event` | `"run"` |
| `timestamp` | `2026-08-19T14:32:07Z` |
| `gitaiflow_version` | `"1.0.0"` |
| `ai_provider` | `"gemini"` |
| `model_name` | `"gemini-flash-lite-latest"` |
| `target_type` | `"file"` \| `"directory"` |
| `files_changed_count` | `4` |
| `tokens_estimated_in` / `tokens_estimated_out` | `1832` / `210` |
| `duration_ms` | `2140` |
| `success` | `true` |
| `os` | `"linux"` |

**🔒 NEVER SENT, EVEN WITH TELEMETRY ON:** repository name, file paths, file contents, diff content, Git author/branch, commit messages, or the AI-generated summary text.

> On the first telemetry-enabled run, Gitaiflow prints the exact payload to stdout so this is verifiable, not just promised.


## Limitations

- An AI provider is mandatory -- gitaiflow does nothing without one
  configured, by design (see "Configure an AI provider" above).
- Daily run/token limits are a local, deletable courtesy check, not
  real enforcement. There's no license/quota server behind them.
- Secret redaction (`.env`, `*_API_KEY`, `*_SECRET_KEY`, etc.) is
  best-effort pattern matching on the diff -- always review generated
  summaries before sharing them outside your team.
- Token/cost estimates in the usage log are a rough `len(text) / 4`
  heuristic, not provider-accurate billing.



- Hosted model-routing backend for a future paid tier.
- Server-side license/quota enforcement.
- PR-platform integration (auto-post summaries to GitHub/GitLab).
- Diff/summary caching across runs.
