<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: erico964-blip</title>
    <description>The latest articles on DEV Community by erico964-blip (@erico964blip).</description>
    <link>https://dev.to/erico964blip</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4010104%2F20d4e2db-157d-4975-9d31-3b93063d9214.png</url>
      <title>DEV Community: erico964-blip</title>
      <link>https://dev.to/erico964blip</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erico964blip"/>
    <language>en</language>
    <item>
      <title>How I Built an AI-Powered Conventional Commit Generator in Python</title>
      <dc:creator>erico964-blip</dc:creator>
      <pubDate>Tue, 30 Jun 2026 20:59:59 +0000</pubDate>
      <link>https://dev.to/erico964blip/how-i-built-an-ai-powered-conventional-commit-generator-in-python-2fgb</link>
      <guid>https://dev.to/erico964blip/how-i-built-an-ai-powered-conventional-commit-generator-in-python-2fgb</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I shipped my first Python CLI to PyPI this week. Here's what I learned building &lt;span class="gs"&gt;**gitpulse**&lt;/span&gt; — a tool that reads your staged git diff and generates Conventional Commit messages using AI.

&lt;span class="gu"&gt;## The Problem&lt;/span&gt;

Every developer has lazy commits in their history:
&lt;span class="sb"&gt;`git commit -m "fix"`&lt;/span&gt;
&lt;span class="sb"&gt;`git commit -m "update"`&lt;/span&gt;
&lt;span class="sb"&gt;`git commit -m "stuff"`&lt;/span&gt;

Clean commit histories matter — for changelogs, code reviews, and your future self trying to understand why you changed that line 6 months ago. But writing &lt;span class="sb"&gt;`feat(auth): add JWT token validation with refresh support`&lt;/span&gt; for every single commit is mental overhead nobody needs.

&lt;span class="gu"&gt;## The Solution&lt;/span&gt;

gitpulse reads your staged diff and generates the message for you:

&lt;span class="sb"&gt;`pip install gitpulse-commit`&lt;/span&gt;
&lt;span class="sb"&gt;`git add src/auth.py`&lt;/span&gt;
&lt;span class="sb"&gt;`git-pulse`&lt;/span&gt;
&lt;span class="sb"&gt;`# → feat(auth): add JWT token validation`&lt;/span&gt;

You confirm, edit, or abort. One key. Done.

&lt;span class="gu"&gt;## What I Learned&lt;/span&gt;

&lt;span class="gu"&gt;### 1. PyPI packaging is simpler than it looks&lt;/span&gt;

&lt;span class="sb"&gt;`pyproject.toml`&lt;/span&gt; + &lt;span class="sb"&gt;`python -m build`&lt;/span&gt; + &lt;span class="sb"&gt;`twine upload`&lt;/span&gt; is all you need. No &lt;span class="sb"&gt;`setup.py`&lt;/span&gt;, no &lt;span class="sb"&gt;`setup.cfg`&lt;/span&gt;. The hardest part was finding an available package name (hint: check PyPI before you start coding).

&lt;span class="gu"&gt;### 2. ABC + factory pattern for pluggable providers&lt;/span&gt;

The core &lt;span class="sb"&gt;`AIClient`&lt;/span&gt; is abstract. Each provider (OpenCode, OpenAI, Ollama) implements &lt;span class="sb"&gt;`generate(diff) -&amp;gt; str`&lt;/span&gt;. The factory function just does &lt;span class="sb"&gt;`return OpenAIClient(...)`&lt;/span&gt; based on a string. Adding a new provider is ~20 lines of code.

&lt;span class="gu"&gt;### 3. Prompt engineering is API design&lt;/span&gt;

The system prompt is the most important file in the project. It enforces:
&lt;span class="p"&gt;-&lt;/span&gt; Conventional Commits format (&lt;span class="sb"&gt;`type(scope): description`&lt;/span&gt;)
&lt;span class="p"&gt;-&lt;/span&gt; 72-character max
&lt;span class="p"&gt;-&lt;/span&gt; No markdown, no explanations, no fluff
&lt;span class="p"&gt;-&lt;/span&gt; Imperative mood, no period at end

If the AI ignores any of these, the CLI still strips markdown and truncates — defense in depth.

&lt;span class="gu"&gt;### 4. Git hooks are easy but fragile&lt;/span&gt;

&lt;span class="sb"&gt;`git-pulse init`&lt;/span&gt; writes a prepare-commit-msg hook. It works great, but detecting an existing hook without breaking it required a sentinel marker (&lt;span class="sb"&gt;`## GITPULSE_HOOK_V0.1`&lt;/span&gt;) rather than just searching for a comment string.

&lt;span class="gu"&gt;### 5. GitHub Actions CI/CD is a superpower&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
yaml&lt;br&gt;
on:&lt;br&gt;
  push:&lt;br&gt;
    tags:&lt;br&gt;
      - 'v*'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Now `git tag v0.2.0 &amp;amp;&amp;amp; git push --tags` automatically publishes to PyPI. Zero manual steps.

## The Code

7 modules, ~300 lines of Python:
- `cli.py` — argparse with subcommands
- `ai_client.py` — ABC + 3 providers
- `git_ops.py` — subprocess wrappers
- `hook.py` — git hook installer
- `config.py` — env var getters
- `prompts.py` — the system prompt
- `__init__.py` — version

Only dependency: `requests`. Python 3.8+. MIT license.

## Try It

`pip install gitpulse-commit`

GitHub: [erico964-blip/gitpulse](https://github.com/erico964-blip/gitpulse)
PyPI: [gitpulse-commit](https://pypi.org/project/gitpulse-commit/)

Built this over a weekend. Feedback welcome — especially on the prompt design and hook workflow!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
      <category>python</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
