tharlesamaro/laravel-git-ai

AI-powered Git workflow automation for Laravel: smart commit messages, changelog generation, and commit validation using Conventional Commits.

Installs: 2

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/tharlesamaro/laravel-git-ai

v0.3.0 2026-02-11 13:53 UTC

This package is auto-updated.

Last update: 2026-02-11 13:54:12 UTC


README

Latest Version on Packagist Total Downloads

English | Portugues

AI-powered Git workflow automation for Laravel. Generate smart commit messages, changelogs, and validate commits using Conventional Commits.

Why use this package instead of Claude Code directly?

If you already use Claude Code CLI, you might wonder: "Why not just ask Claude to commit for me?" Here's what this package brings to the table:

Feature Claude Code alone Laravel Git AI
Conventional Commits format You have to ask every time Enforced automatically via structured output
Consistent JSON schema Free-form text, may vary Validated against a strict schema every time
Project-specific scopes Must remember to mention them Configured once, enforced on every commit
Allowed commit types Manual discipline Restricted by config, AI cannot use others
Multi-language support Must specify in every prompt Configured once, always applied
Changelog generation Manual work Automated from commit history between tags
Git hook validation Not available Optional hook rejects non-conventional commits
Team consistency Each developer prompts differently Same rules for everyone via shared config
Max diff size control No control, may exceed context Auto-truncated to configured limit
Works without CLI installed N/A Falls back to API providers (Anthropic/OpenAI)

In short: this package turns AI-generated commits into a repeatable, team-wide standard instead of a one-off prompt.

Features

  • git:commit -- Generate commit messages from staged changes using AI, following Conventional Commits
  • git:changelog -- Generate structured changelogs from commit history between tags
  • git:setup -- Interactive configuration wizard
  • 3 providers -- Anthropic API, OpenAI API, or Claude Code CLI (no API key needed)
  • 9 languages -- English, Portuguese, Spanish, French, German, Italian, Japanese, Korean, Chinese
  • Scope enforcement -- Restrict commits to project-specific scopes
  • Type restriction -- Limit which Conventional Commits types are allowed
  • Commit templates -- Built-in (minimal, detailed) and custom presets for body + footer settings
  • Body control -- Configure whether AI always includes body, never includes it, or decides automatically
  • Footer control -- Toggle BREAKING CHANGE footer, add custom footer lines, control Co-Authored-By trailer
  • Git hook -- Optional commit-msg hook to reject non-conventional commits
  • Structured output -- AI responses are validated against a JSON schema, never free-form text
  • Diff truncation -- Large diffs are automatically truncated to fit AI context windows

Requirements

  • PHP 8.4+
  • Laravel 12+
  • One of the following:
    • Laravel AI SDK (laravel/ai) + an API key from Anthropic or OpenAI
    • OR Claude Code CLI installed on your machine (uses your existing Claude subscription, e.g. Max plan -- no API key required)

Installation

composer require tharlesamaro/laravel-git-ai

Publish the configuration file:

php artisan vendor:publish --tag=git-ai-config

Run the interactive setup:

php artisan git:setup

Provider Setup

Option 1: Anthropic API (default)

GIT_AI_PROVIDER=anthropic
ANTHROPIC_API_KEY=your-api-key

Option 2: OpenAI API

GIT_AI_PROVIDER=openai
OPENAI_API_KEY=your-api-key

Option 3: Claude Code CLI (no API key)

If you have a Claude subscription (e.g. Max plan) and the Claude Code CLI installed, you can use it directly without any API key:

GIT_AI_PROVIDER=claude-code

Make sure the claude binary is available in your PATH. Install it from: https://docs.anthropic.com/en/docs/claude-code

This option invokes the Claude Code CLI as a subprocess, passing a structured prompt and parsing the JSON response. It consumes from your existing subscription usage -- no separate API tokens needed.

Usage

git:commit -- Generate a commit message

Stage your changes and run:

php artisan git:commit

Or stage everything automatically with the --all (-a) flag:

php artisan git:commit --all

Available options:

Option Short Description
--all -a Stage all changes before committing
--template= Use a named commit template (e.g. minimal, detailed)
--no-body Strip body from the commit message
--footer= Add custom footer line(s) (can be used multiple times)

What happens:

  1. Reads your staged diff (truncated if it exceeds max_diff_size)
  2. Sends it to the configured AI provider
  3. Receives a structured response with type, scope, description, body, and is_breaking_change
  4. Validates the type and scope against your config
  5. Formats the message following Conventional Commits
  6. Lets you choose what to do next

Interactive menu:

Staged changes:
 src/Models/User.php    | 12 ++++++---
 src/Http/AuthController.php | 8 ++++--
 2 files changed, 14 insertions(+), 6 deletions(-)

Generated commit message:
  feat(auth): add email verification on registration

What would you like to do?
  > Accept and commit
    Edit the message
    Generate a new suggestion
    Cancel
  • Accept and commit -- Creates the commit with the generated message
  • Edit the message -- Opens an editor to modify the title and body separately
  • Generate a new suggestion -- Calls the AI again for a different message
  • Cancel -- Aborts without committing

Example with body and breaking change:

Generated commit message:
  feat(api)!: replace REST endpoints with GraphQL

  Migrate all API endpoints from REST to GraphQL.
  This removes all /api/v1/* routes.

  BREAKING CHANGE: replace REST endpoints with GraphQL

git:changelog -- Generate a changelog

php artisan git:changelog

Available options:

Option Description Default
--from= Starting tag or commit hash Latest tag (or first commit if no tags)
--to= Ending tag or commit hash HEAD
--tag= Version tag for the changelog header Interactive prompt
--dry-run Preview without writing to file false

Examples:

# Auto-detect range (latest tag to HEAD)
php artisan git:changelog

# From a specific tag to HEAD
php artisan git:changelog --from=v1.0.0

# Between two references
php artisan git:changelog --from=v1.0.0 --to=v1.1.0

# Specify the version tag upfront
php artisan git:changelog --tag=v2.0.0

# Preview without writing to file
php artisan git:changelog --dry-run

# Combine options
php artisan git:changelog --from=v1.0.0 --to=v2.0.0 --tag=v2.0.0 --dry-run

What happens:

  1. Resolves the starting reference (priority: --from > latest tag > first commit)
  2. Gets all commits between from and to
  3. Parses each commit message using the Conventional Commits format
  4. Groups commits by type (feat, fix, docs, etc.)
  5. Sends the grouped commits to the AI for human-readable descriptions
  6. Formats the output as Markdown with emojis (configurable)
  7. Shows a preview and asks for confirmation before writing

Output example (CHANGELOG.md):

## [v1.2.0] - 2026-02-11

### Features

- Add email verification during user registration
- Implement password reset via SMS

### Bug Fixes

- Resolve null pointer when loading user preferences
- Fix timezone handling in scheduled notifications

### Documentation

- Update API authentication guide with OAuth2 examples

If changelog.with_emojis is enabled (default), section titles include emojis:

### โœจ Features
### ๐Ÿ› Bug Fixes
### ๐Ÿ“š Documentation
### โ™ป๏ธ Code Refactoring
### โšก Performance Improvements
### ๐Ÿงช Tests
### ๐Ÿ“ฆ Build System
### ๐Ÿ”ง Continuous Integration
### ๐Ÿ”จ Chores
### โช Reverts

The changelog is prepended to the existing file. If CHANGELOG.md already exists, new content is added at the top (below the header), preserving previous entries.

git:setup -- Interactive configuration

php artisan git:setup

The wizard walks you through every configurable option:

  1. AI provider -- Anthropic API, OpenAI API, or Claude Code CLI
  2. Language -- English, Portuguese (Brazil), Spanish, French, German, Italian, Japanese, Korean, or Chinese
  3. Scopes -- Define allowed scopes for your project (e.g., auth, api, ui, database)
  4. Types -- Restrict which commit types are allowed (e.g., only feat, fix, docs)
  5. Body preference -- How the AI handles commit message body (auto, always, never)
  6. Git hook -- Install a commit-msg hook that rejects non-conventional commits

After setup, it writes config/git-ai.php and shows the environment variables you need to add to .env.

Configuration

All options in config/git-ai.php:

return [

    // AI provider: 'anthropic', 'openai', or 'claude-code'
    'provider' => env('GIT_AI_PROVIDER', 'anthropic'),

    // AI model override (null = provider default)
    // Examples: 'claude-sonnet-4-5-20250929', 'gpt-4o', etc.
    'model' => env('GIT_AI_MODEL'),

    // Language for commit messages and changelog entries
    // Supported: 'en', 'pt-BR', 'es', 'fr', 'de', 'it', 'ja', 'ko', 'zh'
    'language' => env('GIT_AI_LANGUAGE', 'en'),

    // Allowed commit scopes (empty array = any scope allowed)
    // The AI will only use scopes from this list
    // Example: ['auth', 'api', 'ui', 'database', 'config']
    'scopes' => [],

    // Allowed commit types (empty array = all Conventional Commits types allowed)
    // The AI will only use types from this list
    // Example: ['feat', 'fix', 'docs', 'refactor', 'test']
    'types' => [],

    // Maximum diff size sent to the AI (in characters)
    // Diffs larger than this are truncated with a warning
    'max_diff_size' => env('GIT_AI_MAX_DIFF_SIZE', 15000),

    // Commit message settings
    'commit' => [

        // Body behavior: 'auto' (AI decides), 'always' (AI must include), 'never' (stripped from output)
        'body' => env('GIT_AI_COMMIT_BODY', 'auto'),

        // Footer settings
        'footer' => [

            // Whether to include the BREAKING CHANGE footer when applicable
            'breaking_change' => true,

            // Whether to include a "Co-Authored-By" trailer in commit messages
            // Set to false to prevent AI attribution lines in commits
            'co_authored_by' => env('GIT_AI_CO_AUTHORED_BY', false),

            // Custom footer lines to append to every commit message
            // Example: ['Signed-off-by: Name <email@example.com>']
            'lines' => [],
        ],
    ],

    // Named presets that bundle body + footer settings
    // Built-in templates: 'minimal', 'detailed'
    'templates' => [

        // Default template (null = no template, use 'commit' settings directly)
        'default' => env('GIT_AI_TEMPLATE'),

        // Custom template definitions
        'presets' => [
            // 'my-team' => [
            //     'body' => 'always',
            //     'footer' => [
            //         'breaking_change' => true,
            //         'co_authored_by' => false,
            //         'lines' => ['Signed-off-by: Team <team@example.com>'],
            //     ],
            // ],
        ],
    ],

    // Changelog generation settings
    'changelog' => [

        // File path relative to project root
        'path' => 'CHANGELOG.md',

        // Include emojis in section titles (e.g., "### โœจ Features")
        'with_emojis' => true,
    ],

    // Git hook settings
    'hook' => [

        // Whether the commit-msg validation hook is enabled
        'enabled' => false,

        // When true, rejects non-conventional commits
        // When false, only displays a warning
        'strict' => true,
    ],

];

Environment variables

Variable Description Default
GIT_AI_PROVIDER AI provider (anthropic, openai, claude-code) anthropic
GIT_AI_MODEL AI model override Provider default
GIT_AI_LANGUAGE Commit message language en
GIT_AI_MAX_DIFF_SIZE Max diff size in characters 15000
GIT_AI_COMMIT_BODY Body behavior (auto, always, never) auto
GIT_AI_CO_AUTHORED_BY Include Co-Authored-By trailer false
GIT_AI_TEMPLATE Default commit template name --
ANTHROPIC_API_KEY Anthropic API key (when provider is anthropic) --
OPENAI_API_KEY OpenAI API key (when provider is openai) --

Commit Templates

Templates bundle body and footer preferences into named presets. They're entirely optional -- without a template, the commit config section is used directly.

Built-in templates

Template Body BREAKING CHANGE footer Use case
minimal Never No Quick, one-line commits
detailed Always Yes Thorough commits with full context

Using templates

# Use a built-in template
php artisan git:commit --template=minimal

# Override body on the fly
php artisan git:commit --no-body

# Add custom footers
php artisan git:commit --footer="Signed-off-by: Name <email>"
php artisan git:commit --footer="Reviewed-by: Alice" --footer="Tested-by: Bob"

# Combine options
php artisan git:commit --template=detailed --footer="Signed-off-by: Team <team@example.com>"

Set a default template

In your .env:

GIT_AI_TEMPLATE=minimal

Or in config/git-ai.php:

'templates' => [
    'default' => 'minimal',
],

Custom templates

Define your own presets in config/git-ai.php:

'templates' => [
    'default' => null,
    'presets' => [
        'my-team' => [
            'body' => 'always',
            'footer' => [
                'breaking_change' => true,
                'co_authored_by' => false,
                'lines' => ['Signed-off-by: Team <team@example.com>'],
            ],
        ],
        'quick' => [
            'body' => 'never',
            'footer' => [
                'breaking_change' => false,
                'lines' => [],
            ],
        ],
    ],
],

Then use it:

php artisan git:commit --template=my-team

Disabling Co-Authored-By

By default, the Co-Authored-By trailer is not included in commit messages. If you want to enable it:

// config/git-ai.php
'commit' => [
    'footer' => [
        'co_authored_by' => true,
    ],
],

Or via environment variable:

GIT_AI_CO_AUTHORED_BY=true

When enabled, commits will include a trailer like:

Co-Authored-By: Claude <noreply@anthropic.com>

Set it to false (default) to keep commits clean without AI attribution.

Git Hook

The package includes an optional commit-msg git hook that validates commit messages against the Conventional Commits specification.

What it validates:

  • The message must match the format: <type>(<scope>): <description>
  • The type must be one of: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
  • The first line must not exceed 72 characters
  • Merge commits, reverts, fixups, and squashes are automatically allowed

Install the hook:

# Via the setup wizard
php artisan git:setup

# Or manually copy the hook file
cp vendor/tharlesamaro/laravel-git-ai/stubs/commit-msg .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

Example of a rejected commit:

$ git commit -m "updated stuff"

Invalid commit message format!

Your message:
  updated stuff

Expected format:
  <type>(<scope>): <description>

Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert

Examples:
  feat(auth): add OAuth2 login support
  fix: resolve null pointer in user service
  docs(readme): update installation instructions

Tip: Use 'php artisan git:commit' to generate valid messages automatically.

Conventional Commits

This package follows the Conventional Commits v1.0.0 specification:

<type>(<scope>): <description>

[optional body]

[optional footer(s)]

Supported types

Type Emoji Description
feat โœจ A new feature
fix ๐Ÿ› A bug fix
docs ๐Ÿ“š Documentation only changes
style ๐Ÿ’Ž Code style changes (formatting, semicolons, etc.)
refactor โ™ป๏ธ Code refactoring (no feature or fix)
perf โšก Performance improvements
test ๐Ÿงช Adding or fixing tests
build ๐Ÿ“ฆ Build system or dependency changes
ci ๐Ÿ”ง CI configuration changes
chore ๐Ÿ”จ Other changes (tooling, configs, etc.)
revert โช Reverts a previous commit

Breaking changes

Breaking changes are indicated by:

  • An ! after the type/scope: feat(api)!: remove deprecated endpoints
  • A BREAKING CHANGE: footer in the body

The AI detects breaking changes automatically from the diff and sets is_breaking_change accordingly.

Architecture

The package uses a service abstraction layer (AiService contract) that allows swapping between providers without changing command logic:

  • AgentAiService -- Uses the Laravel AI SDK agents with structured output for API-based providers (Anthropic, OpenAI)
  • ClaudeCodeAiService -- Invokes the claude CLI as a subprocess for users with a Claude subscription

The provider is resolved at runtime based on config('git-ai.provider'). Both implementations return the same structured array format, ensuring consistent behavior regardless of the provider.

Testing

composer test

This package uses Pest PHP for testing. To run with coverage:

composer test-coverage

Using Docker:

docker compose run --rm test

Contributing

Contributions are welcome! Please follow Conventional Commits for your commit messages.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feat/amazing-feature)
  3. Commit your changes (php artisan git:commit ๐Ÿ˜„)
  4. Push to the branch (git push origin feat/amazing-feature)
  5. Open a Pull Request

License

The MIT License (MIT). See LICENSE for details.