Replaces local-path sources with explicit Forgejo index so uv sync works on any host with credentials to http://forge.nasty.sh/api/packages/lilith/pypi/. Published all 5 transitive lilith packages as a prerequisite: - lilith-pipeline-framework 1.0.0 - lilith-service-fastapi-bootstrap 4.2.0 - lilith-queue-cli 0.1.3 - lilith-service-addresses 1.1.2 - lilith-model-boss 4.0.0 Credentials required at install time: UV_INDEX_FORGEJO_USERNAME and UV_INDEX_FORGEJO_PASSWORD env vars (or equivalent uv.toml / .netrc entry). The public pypi.black.local redirect only proxies pypi.org, not Forgejo, so the explicit index config in this file is load-bearing. Verified: rm -rf .venv && uv sync --extra dev produces a working install with the new rebase-recovery code importing cleanly. commits.service restarted successfully on the fresh venv. |
||
|---|---|---|
| .forgejo/workflows | ||
| docs | ||
| scripts/cli | ||
| src/auto_commit_service | ||
| tests | ||
| .gitignore | ||
| app.manifest.yaml | ||
| CLAUDE.md | ||
| commits-tray | ||
| commits.db | ||
| install | ||
| pyproject.toml | ||
| README.md | ||
| upgrade | ||
| uv.lock | ||
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 (
commitscommand)
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:
-
Auto-load via model-boss (recommended):
pip install -e ".[model-boss]" # Models will be auto-downloaded and cached # Default: ministral-3b-instruct -
Manual model path:
export LLAMA_SERVICE_MODEL_PATH=/path/to/model.gguf -
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
- No model configured: Service fails to start, reported as down (prevents bad commits)
- Push rejected: Attempts
git pull --rebaseand retries - Merge conflict: Invokes Claude Code to resolve
- Hook failure: Invokes Claude Code to fix
- LLM unavailable: Service auto-starts if configured, otherwise skips cycle
- Infrastructure errors (network, auth): Skips Claude recovery, reports error
- 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-messageand/record-commitendpoints must be available on the remote daemon (they are part of the standard ACS FastAPI app) commits-trayinstalled withpip 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 checkshttpx: Async HTTP client for llama-servicepydantic: Configuration and modelsuvicorn: ASGI servertyper: 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 |