380 lines
12 KiB
Markdown
380 lines
12 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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)**:
|
|
```bash
|
|
pip install -e ".[model-boss]"
|
|
# Models will be auto-downloaded and cached
|
|
# Default: ministral-3b-instruct
|
|
```
|
|
|
|
2. **Manual model path**:
|
|
```bash
|
|
export LLAMA_SERVICE_MODEL_PATH=/path/to/model.gguf
|
|
```
|
|
|
|
3. **Disable auto-start** (use external llama-service):
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
python -m auto_commit_service
|
|
```
|
|
|
|
### Run with uvicorn
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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`:
|
|
|
|
```xml
|
|
<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
|
|
|
|
```bash
|
|
# 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 |
|