No description
Find a file
Natalie a9fa13d242 fix(@ml/auto-commit-service): 🐛 handle staged-only unstage on empty commit
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-10 02:18:15 -07:00
.forgejo/workflows deploy(deploy): 🚀 Update deployment scripts, installation/upgrade processes, and documentation for improved workflow consistency 2026-04-17 21:20:13 -07:00
docs feat(cot-commit): Implement sophisticated COT reasoning logic for auto-commit decision triggers 2026-04-17 21:20:13 -07:00
scripts/cli feat(@ml/auto-commit-service): add initial commit service implementation 2026-01-09 22:17:12 -08:00
src/auto_commit_service fix(@ml/auto-commit-service): 🐛 handle staged-only unstage on empty commit 2026-06-10 02:18:15 -07:00
tests test(daemon): Add test cases for task-based routing behavior in daemon 2026-05-11 08:56:36 -07:00
.gitignore chore(config): 🔧 Update .gitignore to exclude build artifacts, logs, and environment variables 2026-04-17 21:20:13 -07:00
app.manifest.yaml deploy(deploy): 🚀 Update deployment scripts, installation/upgrade processes, and documentation for improved workflow consistency 2026-04-17 21:20:13 -07:00
CLAUDE.md docs(docs): 📝 Add branch synchronization requirements and failure modes documentation to CLAUDE.md 2026-06-09 19:22:47 -07:00
commits-tray feat(@ml/auto-commit-service): add ignore-repo config support 2026-05-13 15:30:46 -07:00
commits.db deploy(deploy): 🚀 Update deployment scripts, installation/upgrade processes, and documentation for improved workflow consistency 2026-04-17 21:20:13 -07:00
install deploy(deploy): 🚀 Update deployment scripts, installation/upgrade processes, and documentation for improved workflow consistency 2026-04-17 21:20:13 -07:00
pyproject.toml deps-upgrade(config): ⬆️ Update dependency versions in pyproject.toml for security and compatibility improvements 2026-05-11 09:02:38 -07:00
README.md deploy(deploy): 🚀 Update deployment scripts, installation/upgrade processes, and documentation for improved workflow consistency 2026-04-17 21:20:13 -07:00
upgrade deploy(deploy): 🚀 Update deployment scripts, installation/upgrade processes, and documentation for improved workflow consistency 2026-04-17 21:20:13 -07:00
uv.lock deps: simplify to default pypi.black.local index 2026-04-18 13:09:53 -07:00

Auto-Commit Service

Automated commit message generation service using local LLM inference. Commits and pushes changes across lilith-platform repos every 15 minutes.

Features

  • Generates commit messages using llama-service (local 3B model)
  • Processes multiple repositories in a cycle
  • Automatic push with conflict resolution
  • Claude Code fallback for complex failures
  • FastAPI endpoints for monitoring and manual triggers
  • CLI for multi-daemon management (commits command)

Installation

# Install the package
cd /var/home/lilith/Code/@packages/@ml/auto-commit-service
pip install -e .

# Or with model-boss integration (recommended)
pip install -e ".[model-boss]"

# Or with dev dependencies
pip install -e ".[dev]"

After installation, the commits CLI is available system-wide.

Model Configuration

The service requires a language model to generate commit messages. You have three options:

  1. Auto-load via model-boss (recommended):

    pip install -e ".[model-boss]"
    # Models will be auto-downloaded and cached
    # Default: ministral-3b-instruct
    
  2. Manual model path:

    export LLAMA_SERVICE_MODEL_PATH=/path/to/model.gguf
    
  3. Disable auto-start (use external llama-service):

    export AUTO_COMMIT_LLAMA_SERVICE_AUTOSTART=false
    

Important: If no model is configured, the service will fail to start and report as down. This prevents making commits with placeholder messages.

CLI Usage

The commits CLI manages multiple auto-commit daemon instances.

Quick Start

# Start daemon for current directory
cd ~/Code/@packages
commits start 5m -R              # Every 5 min, recursive discovery

# Check status
commits status                   # Current directory
commits status --all             # All daemons

# View report
commits report                   # Comprehensive report
commits report -A                # All daemons summary

# Trigger immediate cycle
commits once                     # Refresh repos and commit
commits once -A                  # All daemons

# Stop daemon
commits stop

Commands

Command Description
commits start [interval] [OPTIONS] Start daemon for current directory
commits stop Stop daemon for current directory
commits status [-A] Show daemon status
commits once [-A] Refresh repos and trigger cycle
commits report [-A] [-C N] [--raw] Show comprehensive report
commits recent [-n N] [--full] Show last N commits with relative timestamps
commits trigger Manually trigger a commit cycle
commits enable Enable the daemon
commits disable Disable the daemon
commits logs Tail daemon logs
commits list List all running daemons
commits install-systemd DIR [OPTIONS] Install systemd user service

Start Options

commits start [interval] [OPTIONS]

Options:
  -R, --recursive        Enable recursive git discovery
  --depth INT            Recursion depth limit
  -C, --cache-update STR Cache refresh interval (default: 60m)

Examples:
  commits start 5m              # Every 5 minutes
  commits start -R 1h           # Every hour, recursive
  commits start -R --depth 1 5m # Every 5 min, depth 1

Report Options

commits report [OPTIONS]

Options:
  -A, --all-daemons    Show reports for all daemons
  -C INT               Show last N commits grouped by repo
  --raw                Show raw JSON output

Examples:
  commits report             # Summary for current directory
  commits report -A          # Summary for all daemons
  commits report -C 20       # Last 20 commits

Recent Commits

commits recent [OPTIONS]

Options:
  -n, --limit INT      Number of commits to show (default: 50)
  -f, --full           Fetch actual commit messages from git (slower)
  --raw                Show raw JSON output

Examples:
  commits recent             # Last 50 commits with relative timestamps
  commits recent -n 10       # Last 10 commits
  commits recent --full      # Include actual git commit messages

Systemd Integration

# Install systemd user service
commits install-systemd ~/Code/@packages 5m -R

# Service commands
systemctl --user status commits-var-home-lilith-Code-@packages
systemctl --user stop commits-var-home-lilith-Code-@packages
journalctl --user -u commits-var-home-lilith-Code-@packages -f

Configuration

Environment variables (prefix: AUTO_COMMIT_):

Variable Default Description
AUTO_COMMIT_LLAMA_SERVICE_URL http://localhost:8000 llama-service URL
AUTO_COMMIT_LLAMA_SERVICE_AUTOSTART true Auto-start llama-service if down
AUTO_COMMIT_LLAMA_MODEL_ID qwen2.5-1.5b-instruct Model ID for model-boss
AUTO_COMMIT_USE_MODEL_BOSS true Use model-boss for model loading
AUTO_COMMIT_CYCLE_INTERVAL_SECONDS 900 Seconds between cycles (15 min)
AUTO_COMMIT_ENABLED true Enable daemon on startup
AUTO_COMMIT_CLAUDE_FALLBACK_ENABLED true Enable Claude Code recovery
AUTO_COMMIT_HOST 0.0.0.0 Service host
AUTO_COMMIT_PORT 8200 Service port

Direct Service Usage

If you prefer to run the service directly without the CLI:

Run directly

python -m auto_commit_service

Run with uvicorn

uvicorn auto_commit_service:create_auto_commit_service --host 0.0.0.0 --port 8200

API Endpoints

Endpoint Method Description
/health GET Service health check
/status GET Daemon status and last cycle
/trigger POST Manually trigger a cycle
/enable POST Enable the daemon
/disable POST Disable the daemon
/repos GET List configured repositories
/repos/refresh-and-run POST Refresh repo cache and trigger cycle
/report/summary GET Comprehensive daemon report
/report/commits GET Commit history

Examples

# Check health
curl http://localhost:8200/health

# Get status
curl http://localhost:8200/status

# Trigger manual cycle
curl -X POST http://localhost:8200/trigger

# Disable daemon
curl -X POST http://localhost:8200/disable

Commit Style

Generated commits follow the Lilith Platform convention:

  • feat: New feature
  • 🔧 chore: Maintenance, config changes
  • ♻️ refactor: Code restructuring
  • 🐛 fix: Bug fix
  • 📝 docs: Documentation
  • test: Tests
  • 🔥 remove: Removing code/files

Error Handling

  1. No model configured: Service fails to start, reported as down (prevents bad commits)
  2. Push rejected: Attempts git pull --rebase and retries
  3. Merge conflict: Invokes Claude Code to resolve
  4. Hook failure: Invokes Claude Code to fix
  5. LLM unavailable: Service auto-starts if configured, otherwise skips cycle
  6. Infrastructure errors (network, auth): Skips Claude recovery, reports error
  7. Auth failure: Skips repo (requires manual fix)

Running the tray as a commit proxy (macOS)

The commits-tray menu bar app can run on a Mac (e.g. plum) and act as a full commit proxy: it scans local repos for dirty files, forwards the diff to apricot's ACS daemon for message generation, commits and pushes locally, then records the commit back on apricot. No second daemon process is needed on the Mac.

Prerequisites

  • apricot's ACS daemon must be running and reachable (port 8200 by default)
  • The /generate-message and /record-commit endpoints must be available on the remote daemon (they are part of the standard ACS FastAPI app)
  • commits-tray installed with pip install -e ".[tray]"

Enable proxy mode

# Dry run first — scans and generates messages, but skips git commit/push
./commits-tray --url http://apricot.local:8200 --cycle 300 --commit-local --dry-run

# Enable for real once you've confirmed dry-run output looks correct
./commits-tray --url http://apricot.local:8200 --cycle 300 --commit-local

Flags:

Flag Default Description
--commit-local off Enable the local commit proxy loop. Off by default for safety.
--dry-run off Scan and generate messages but skip git commit/git push.
--max-diff-bytes 131072 Per-repo diff size cap (bytes) before truncation.
--cycle 300 Seconds between commit cycles.

Secret prefilter

Before any diff leaves the Mac for apricot, the prefilter strips all files matching the denylist. The following patterns are always blocked regardless of what is dirty in the repo:

.env  .env.*
*.pem  *.key  *.p12  *.pfx
id_rsa  id_rsa.*  id_dsa  id_dsa.*  id_ecdsa  id_ecdsa.*  id_ed25519  id_ed25519.*
*.asc
.ssh/**  **/.ssh/**
**/secrets.yaml  **/secrets.yml  **/secrets.json
secrets.yaml  secrets.yml  secrets.json
.git/config  .git/credentials  **/.git/config  **/.git/credentials
**/credentials.json  credentials.json
**/.netrc  .netrc
**/*.keystore  *.keystore  **/*.jks  *.jks

Exception: .env.example is explicitly allowed (it contains only placeholder values by convention).

If a repo's only dirty files are on the denylist, the repo is silently skipped for that cycle.

Staging index safety gate

The proxy only commits unstaged and untracked files. If a repo has anything in the staging index (i.e. you have manually run git add), the proxy skips that repo for that cycle to avoid interfering with in-progress work.

LaunchAgent integration

To enable proxy mode persistently, add --commit-local (and optionally --dry-run) to the ProgramArguments array in ~/Library/LaunchAgents/com.lilith.commits-tray.plist:

<key>ProgramArguments</key>
<array>
    <string>/path/to/commits-tray</string>
    <string>--url</string>
    <string>http://apricot.local:8200</string>
    <string>--cycle</string>
    <string>300</string>
    <string>--commit-local</string>
</array>

Reload with launchctl unload / launchctl load after editing the plist.

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=auto_commit_service

Architecture

auto_commit_service/
├── __init__.py         # Package exports
├── __main__.py         # Entry point
├── app.py              # FastAPI application factory
├── config.py           # Settings (AutoCommitSettings)
├── models.py           # Pydantic models
├── cli/                # CLI module
│   ├── __init__.py     # Typer app and commands
│   ├── registry.py     # Daemon registry management
│   └── utils.py        # CLI utilities
├── git/
│   ├── operations.py   # Async git commands
│   ├── repository.py   # Repository abstraction
│   └── diff_parser.py  # Diff summarization
├── llm/
│   ├── client.py       # llama-service HTTP client
│   └── prompts.py      # Commit message prompts
├── scheduler/
│   ├── daemon.py       # Main 900s loop
│   └── processor.py    # Per-repo commit logic
└── recovery/
    ├── handlers.py     # Error type routing
    └── claude_fallback.py  # Claude Code invocation

Dependencies

  • lilith-ml-service-base: FastAPI patterns, lifespan, health checks
  • httpx: Async HTTP client for llama-service
  • pydantic: Configuration and models
  • uvicorn: ASGI server
  • typer: CLI framework

Configuration Files

File Location Purpose
Daemon registry ~/.config/commits/daemons.json Tracks running daemon instances
Logs /tmp/auto-commit-{port}.log Per-daemon log files