Metadata-Version: 2.4
Name: gitaiflow
Version: 1.0.0
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

<div>
  <img
    src="gitaiflow/static/assets/logo/icon.png"
    height="20"
    alt="DjangoPlay icon"
  >
  <img
    src="gitaiflow/static/assets/logo/name.png"
    height="16"
    alt="DjangoPlay"
  >
</div>
<p>
  Maintained by: <a href="https://djangoplay.org">[DjangoPlay](https://djangoplay.org)</a>
</p>

[![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)
[![Coverage](https://img.shields.io/codecov/c/github/codefleetx/gitaiflow)](https://codecov.io/gh/codefleetx/gitaiflow)
[![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)


A standalone OpenID Connect (OIDC) identity microservice, built with FastAPI, plus a small Django client for services that need to talk to it.


---


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. Pick whichever fits:

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

```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, OpenRouter, 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` | `1024` | |
| `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": "Merc", "email": "merc@example.com" },
  "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 -- it is not a separate project and not
something copied by hand onto the server. This matters because
production deployment relies on `git pull` bringing it along
automatically (see `telemetry_server/DEPLOY.md`).

```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.djangoplay.org -- see telemetry_server/DEPLOY.md
│   ├── app.py
│   ├── requirements.txt
│   ├── gitaiflow-telemetry.service
│   ├── nginx-conf.d-gitaiflow-telemetry-ratelimit.conf
│   ├── nginx-location-snippet.conf
│   └── DEPLOY.md
├── .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 this, to
`https://app.djangoplay.org/gitaiflow-telemetry/v1/events` (the
maintainer's self-hosted receiver -- see `telemetry_server/` above
and its `DEPLOY.md` for how it's run), 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.

## Roadmap (not yet built)

- 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.
