deploy(deploy): 🚀 Update deployment scripts, installation/upgrade processes, and documentation for improved workflow consistency
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
3cff601331
commit
809681f042
8 changed files with 948 additions and 5 deletions
48
.forgejo/workflows/deploy.yml
Normal file
48
.forgejo/workflows/deploy.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# =============================================================================
|
||||
# Auto-Deploy Workflow
|
||||
# =============================================================================
|
||||
# Deploys auto-commit-service to the local host after successful publish.
|
||||
# Triggers on push to main/master and updates the running systemd service.
|
||||
# =============================================================================
|
||||
|
||||
name: Deploy to Host
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
paths:
|
||||
- 'pyproject.toml'
|
||||
- 'src/**'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DEPLOY_HOST: localhost
|
||||
SERVICE_PATH: /var/home/lilith/Code/@applications/@ml/auto-commit-service
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy to Host
|
||||
runs-on: ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy via SSH
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
username: ${{ secrets.DEPLOY_USER }}
|
||||
key: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||
port: ${{ secrets.DEPLOY_PORT || 22 }}
|
||||
script: |
|
||||
set -e
|
||||
echo "==> Pulling latest changes..."
|
||||
cd ${{ env.SERVICE_PATH }}
|
||||
git pull origin main
|
||||
|
||||
echo "==> Running upgrade script..."
|
||||
./upgrade
|
||||
|
||||
echo "==> Deployment complete!"
|
||||
systemctl --user status commits.service --no-pager || true
|
||||
115
CLAUDE.md
Normal file
115
CLAUDE.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Install
|
||||
uv pip install -e . # basic
|
||||
uv pip install -e ".[dev]" # with test deps
|
||||
|
||||
# Tests
|
||||
pytest # unit/smoke tests (GPU tests excluded by default)
|
||||
pytest tests/test_daemon.py -v # single file
|
||||
pytest tests/test_daemon.py::TestDaemon::test_start -v # single test
|
||||
pytest -m gpu -v # GPU integration tests (needs model-boss coordinator running)
|
||||
pytest --cov=auto_commit_service # with coverage
|
||||
|
||||
# Lint/type check
|
||||
ruff check src/ tests/
|
||||
ruff format src/ tests/
|
||||
mypy src/
|
||||
|
||||
# Run service
|
||||
python -m auto_commit_service # direct entry
|
||||
commits start 5m -R # CLI: daemon with 5m cycle, recursive discovery
|
||||
commits status --all # check all running daemons
|
||||
|
||||
# Systemd
|
||||
systemctl --user restart auto-commit-applications.service
|
||||
journalctl --user -u auto-commit-applications -f
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
**Periodic sweep + synchronous queue-mediated inference.** The daemon loops every `cycle_interval_seconds` (default 180s), processes repos sequentially, and each LLM call blocks on model-boss coordinator's queue. The `commits-tray` macOS app can also act as a remote commit agent: with `--commit-local`, it scans repos on the local Mac, forwards diffs to apricot's `/generate-message` endpoint for LLM inference, commits and pushes locally, and reports back via `/record-commit` — no second daemon needed on the Mac.
|
||||
|
||||
### Execution flow
|
||||
|
||||
```
|
||||
CommitDaemon.start() — main loop
|
||||
for each dirty repo:
|
||||
PipelineCommitProcessor.commit_repo()
|
||||
→ Pipeline orchestrator (11 stages):
|
||||
PreFilter → Discover → Retrieve(RAG) → Group → Analyze(14B) → Format(3B)
|
||||
→ Commit → Push → VersionDetect → PublishVerify → Recover
|
||||
→ Each LLM stage calls MultiModelLlamaClient._chat()
|
||||
→ InferenceClient.chat() → POST coordinator:8210/v1/chat/completions
|
||||
→ model-boss coordinator queues and executes on GPU
|
||||
sleep(cycle_interval_seconds)
|
||||
```
|
||||
|
||||
### Two-model LLM pipeline
|
||||
|
||||
All inference routes through **model-boss coordinator** (port 8210). No direct model loading.
|
||||
|
||||
- **Reasoning** (`ministral-14b-reasoning`): Analyzes diffs, groups files, understands changes
|
||||
- **Instruct** (`ministral-3b-instruct`): Formats commit messages from analysis
|
||||
- **Recovery** (`claude:sonnet` via model-boss): Two-phase recovery for git failures — Claude diagnoses, ACS executes the plan locally
|
||||
|
||||
### Key modules
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `scheduler/daemon.py` | Main loop, cycle orchestration, repo discovery |
|
||||
| `scheduler/pipeline_processor.py` | Per-repo processing, monorepo submodule handling |
|
||||
| `pipeline/orchestrator.py` | Creates the 11-stage pipeline chain |
|
||||
| `pipeline/stages/` | Individual pipeline stages |
|
||||
| `pipeline/init.py` | Global ML provider initialization (must call before pipeline) |
|
||||
| `llm/multi_model_client.py` | Routes inference to model-boss via InferenceClient |
|
||||
| `recovery/handlers.py` | Error classification → recovery strategy routing |
|
||||
| `recovery/claude_fallback.py` | Two-phase Claude recovery (diagnose via model-boss, execute locally) |
|
||||
| `database/` | Async SQLite (aiosqlite) for commit/cycle/error history |
|
||||
| `cli/` | Typer CLI (`commits` command) for multi-daemon management |
|
||||
| `app.py` | FastAPI factory with 20+ monitoring/control endpoints |
|
||||
| `config.py` | All settings with `AUTO_COMMIT_` env prefix |
|
||||
|
||||
### External dependencies
|
||||
|
||||
- **model-boss coordinator** (port 8210): GPU model management, inference queue, VRAM scheduling
|
||||
- **rag-retrieval** (optional): Contextual retrieval for commit analysis
|
||||
- **git**: All operations via `asyncio.create_subprocess_exec` (no shell)
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings via env vars prefixed `AUTO_COMMIT_` or `~/.config/commits/startup-config.json`.
|
||||
|
||||
Key settings: `REASONING_MODEL_ID`, `INSTRUCT_MODEL_ID`, `CYCLE_INTERVAL_SECONDS`, `CLAUDE_FALLBACK_ENABLED`, `CLAUDE_RECOVERY_MODEL`.
|
||||
|
||||
Per-directory git identity and push behavior via `directory_overrides` in config.
|
||||
|
||||
## Testing
|
||||
|
||||
- `asyncio_mode = "auto"` — all async tests run automatically
|
||||
- GPU tests require model-boss coordinator running, marked `@pytest.mark.gpu`
|
||||
- Fixtures: `temp_git_repo` (creates temp git repo), `mock_settings` (unit), `gpu_settings` (integration)
|
||||
- ruff: line-length 100, select E,F,I,N,W,UP,B,C4,SIM,RUF,PTH,ERA
|
||||
- mypy: strict mode, Python 3.11+
|
||||
|
||||
## Data paths
|
||||
|
||||
| Path | Contents |
|
||||
|------|----------|
|
||||
| `~/.cache/commits/auto_commit.db` | SQLite: commits, cycles, errors, repo status |
|
||||
| `~/.cache/commits/activity.jsonl` | Activity log (JSON Lines) |
|
||||
| `~/.cache/commits/auto-commit.log` | Rotated log file |
|
||||
| `~/.config/commits/startup-config.json` | Daemon registry config |
|
||||
| `~/.config/commits/daemons.json` | Running daemon instances |
|
||||
|
||||
## Important notes
|
||||
|
||||
- **Never commit from this repo** — ACS itself handles all commits across the workspace
|
||||
- Pipeline stages access ML providers via globals initialized by `init_ml_providers()` — must be called before pipeline execution
|
||||
- ACS uses `default_priority="batch"` (lowest) in model-boss queue, so interactive requests preempt it
|
||||
- Recovery commands are validated against an allowlist (no `--force`, `--hard`, `--no-verify`)
|
||||
102
README.md
102
README.md
|
|
@ -86,6 +86,7 @@ commits stop
|
|||
| `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 |
|
||||
|
|
@ -125,6 +126,22 @@ Examples:
|
|||
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
|
||||
|
|
@ -221,6 +238,91 @@ Generated commits follow the Lilith Platform convention:
|
|||
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
|
||||
|
|
|
|||
25
app.manifest.yaml
Normal file
25
app.manifest.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
name: auto-commit-service
|
||||
description: Automated commit message generation using local LLM inference
|
||||
type: daemon-service
|
||||
category: services
|
||||
|
||||
platforms:
|
||||
apricot:
|
||||
os: linux
|
||||
host: apricot.local
|
||||
environment: production
|
||||
services:
|
||||
commits:
|
||||
type: systemd-user
|
||||
systemdUnit: commits
|
||||
port: "8200"
|
||||
description: Auto-commit daemon for ~/Code
|
||||
enabled: true
|
||||
install:
|
||||
path: ~/Code/@applications/@ml/auto-commit-service
|
||||
script: ./install
|
||||
status:
|
||||
command: "systemctl --user is-active commits"
|
||||
type: systemd
|
||||
logs:
|
||||
command: "journalctl --user -u commits -n 100"
|
||||
39
commits-tray
39
commits-tray
|
|
@ -3,10 +3,12 @@
|
|||
|
||||
Manages a lightweight commit agent that discovers local repos, asks the
|
||||
remote ACS daemon for LLM-generated commit messages, and commits+pushes.
|
||||
Runs without the full auto_commit_service package — only needs httpx + rumps.
|
||||
|
||||
Usage:
|
||||
./commits-tray --url http://apricot.local:8200
|
||||
./commits-tray --url http://apricot.local:8200 --repos ~/Code --cycle 300
|
||||
./commits-tray --url http://apricot.local:8200 --cycle 300
|
||||
./commits-tray --url http://apricot.local:8200 --commit-local --dry-run
|
||||
./commits-tray --url http://apricot.local:8200 --commit-local # for real
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
|
@ -14,12 +16,11 @@ import os
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add the tray module directory so we can import directly
|
||||
_script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
_tray_dir = os.path.join(_script_dir, "src", "auto_commit_service", "tray")
|
||||
sys.path.insert(0, _tray_dir)
|
||||
|
||||
from app import run_tray # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="ACS menu bar app + local commit agent")
|
||||
|
|
@ -40,10 +41,38 @@ def main():
|
|||
default=300,
|
||||
help="Seconds between commit cycles (default: 300)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--commit-local",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Enable local commit loop on this host (proxy mode). Default OFF.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Scan and generate messages but skip git commit/push. Useful for validation.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--max-diff-bytes",
|
||||
type=int,
|
||||
default=131072,
|
||||
help="Per-repo diff size cap in bytes before truncation (default: 131072)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Import after argparse so --help exits cleanly before rumps is required
|
||||
from app import run_tray # noqa: E402
|
||||
|
||||
repos_paths = [Path(p).expanduser() for p in args.repos] if args.repos else None
|
||||
run_tray(daemon_url=args.url, repos_paths=repos_paths, cycle_seconds=args.cycle)
|
||||
run_tray(
|
||||
daemon_url=args.url,
|
||||
repos_paths=repos_paths,
|
||||
commit_local=args.commit_local,
|
||||
dry_run=args.dry_run,
|
||||
max_diff_bytes=args.max_diff_bytes,
|
||||
cycle_seconds=args.cycle,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
0
commits.db
Normal file
0
commits.db
Normal file
457
install
Executable file
457
install
Executable file
|
|
@ -0,0 +1,457 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Install auto-commit-service with full ML pipeline
|
||||
# =============================================================================
|
||||
# This script:
|
||||
# 1. Installs auto-commit-service Python package
|
||||
# 2. Sets up model-boss-coordinator + multi-model llama-http services
|
||||
# 3. Starts RAG retrieval service
|
||||
# 4. Creates config files and systemd services
|
||||
# 5. Enables lingering for persistent services
|
||||
#
|
||||
# Dependencies:
|
||||
# - Redis (for model-boss coordination)
|
||||
# - Redis Stack (for RAG vector search) - port 6384
|
||||
# - GPU with CUDA (for local inference)
|
||||
#
|
||||
# Services started:
|
||||
# - model-boss-coordinator (port 8210) - GPU/VRAM lease management
|
||||
# - llama-http-3b (port 10010) - ministral-3b-instruct (formatting)
|
||||
# - llama-http-14b (port 10020) - ministral-14b-reasoning (analysis)
|
||||
# - rag-retrieval (port 8111) - context retrieval
|
||||
# - commits-packages (port 8200) - auto-commit daemon for @packages
|
||||
# - commits-applications (port 8201) - auto-commit daemon for @applications
|
||||
# - commits-projects (port 8202) - auto-commit daemon for @projects
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# Paths
|
||||
MODEL_BOSS_ROOT="/var/home/lilith/Code/@applications/@model-boss"
|
||||
LLAMA_HTTP_PATH="$MODEL_BOSS_ROOT/services/llama-http/service"
|
||||
COORDINATOR_PATH="$MODEL_BOSS_ROOT/services/coordinator/service"
|
||||
RAG_PATH="/var/home/lilith/Code/@applications/@ml/rag-retrieval"
|
||||
|
||||
echo "==> Installing auto-commit-service..."
|
||||
|
||||
# =============================================================================
|
||||
# Step 1: Check prerequisites
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "==> Checking prerequisites..."
|
||||
|
||||
# Check Redis
|
||||
if ! redis-cli ping >/dev/null 2>&1; then
|
||||
echo " ERROR: Redis not running on localhost:6379"
|
||||
echo " Run: brew services start redis"
|
||||
exit 1
|
||||
fi
|
||||
echo " ✓ Redis available"
|
||||
|
||||
# Check Redis Stack (for RAG)
|
||||
if ! redis-cli -p 6384 MODULE LIST 2>/dev/null | grep -q "search"; then
|
||||
echo " WARNING: Redis Stack not found on port 6384"
|
||||
echo " RAG will not work without Redis Stack"
|
||||
echo " Looking for existing Redis Stack containers..."
|
||||
if podman ps 2>/dev/null | grep -q "redis-stack"; then
|
||||
echo " ✓ Redis Stack container found"
|
||||
else
|
||||
echo " Consider starting: podman run -d --name rag-redis -p 6384:6379 redis/redis-stack:latest"
|
||||
fi
|
||||
else
|
||||
echo " ✓ Redis Stack available on port 6384"
|
||||
fi
|
||||
|
||||
# Check GPU
|
||||
if ! command -v nvidia-smi >/dev/null 2>&1; then
|
||||
echo " WARNING: nvidia-smi not found - GPU inference may not work"
|
||||
else
|
||||
GPU_COUNT=$(nvidia-smi -L 2>/dev/null | wc -l)
|
||||
echo " ✓ $GPU_COUNT GPU(s) detected"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Step 2: Install Python packages
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "==> Installing Python packages..."
|
||||
|
||||
# Auto-commit service
|
||||
if [[ ! -d "$SCRIPT_DIR/.venv" ]]; then
|
||||
echo " Creating auto-commit-service venv..."
|
||||
python -m venv "$SCRIPT_DIR/.venv"
|
||||
fi
|
||||
echo " Installing auto-commit-service..."
|
||||
"$SCRIPT_DIR/.venv/bin/pip" install -e "$SCRIPT_DIR" --quiet
|
||||
|
||||
# Model-boss coordinator
|
||||
if [[ -d "$COORDINATOR_PATH" ]]; then
|
||||
if [[ ! -d "$COORDINATOR_PATH/.venv" ]]; then
|
||||
echo " Creating model-boss-coordinator venv..."
|
||||
python -m venv "$COORDINATOR_PATH/.venv"
|
||||
fi
|
||||
echo " Installing model-boss-coordinator..."
|
||||
"$COORDINATOR_PATH/.venv/bin/pip" install -e "$COORDINATOR_PATH" --quiet
|
||||
fi
|
||||
|
||||
# Llama HTTP service
|
||||
if [[ -d "$LLAMA_HTTP_PATH" ]]; then
|
||||
if [[ ! -d "$LLAMA_HTTP_PATH/.venv" ]]; then
|
||||
echo " Creating llama-http venv..."
|
||||
python -m venv "$LLAMA_HTTP_PATH/.venv"
|
||||
fi
|
||||
echo " Installing llama-http..."
|
||||
"$LLAMA_HTTP_PATH/.venv/bin/pip" install -e "$LLAMA_HTTP_PATH" --quiet
|
||||
fi
|
||||
|
||||
# RAG retrieval service
|
||||
if [[ -d "$RAG_PATH" ]]; then
|
||||
if [[ ! -d "$RAG_PATH/.venv" ]]; then
|
||||
echo " Creating rag-retrieval venv..."
|
||||
python -m venv "$RAG_PATH/.venv"
|
||||
fi
|
||||
echo " Installing rag-retrieval..."
|
||||
"$RAG_PATH/.venv/bin/pip" install -e "$RAG_PATH" --quiet
|
||||
fi
|
||||
|
||||
echo " ✓ Python packages installed"
|
||||
|
||||
# =============================================================================
|
||||
# Step 3: Create config files
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "==> Creating config files..."
|
||||
mkdir -p ~/.config/commits
|
||||
|
||||
cat > ~/.config/commits/startup-config.json << 'EOF'
|
||||
{
|
||||
"daemons": [
|
||||
{
|
||||
"id": "packages",
|
||||
"directory": "/var/home/lilith/Code/@packages",
|
||||
"port": 8200,
|
||||
"interval_seconds": 300,
|
||||
"recursive": true,
|
||||
"recursive_depth": 4,
|
||||
"cache_update_minutes": 60,
|
||||
"ignore_repos": [
|
||||
".archive",
|
||||
"_archive",
|
||||
".deprecated"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"node_modules",
|
||||
"pyvenv",
|
||||
".venv",
|
||||
"venv",
|
||||
"dist",
|
||||
"build",
|
||||
"__pycache__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "applications",
|
||||
"directory": "/var/home/lilith/Code/@applications",
|
||||
"port": 8201,
|
||||
"interval_seconds": 300,
|
||||
"recursive": true,
|
||||
"recursive_depth": 4,
|
||||
"cache_update_minutes": 60,
|
||||
"ignore_repos": [
|
||||
".archive",
|
||||
"_archive",
|
||||
"egirl-platform",
|
||||
".deprecated"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"node_modules",
|
||||
"pyvenv",
|
||||
".venv",
|
||||
"venv",
|
||||
"dist",
|
||||
"build",
|
||||
"__pycache__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "projects",
|
||||
"directory": "/var/home/lilith/Code/@projects",
|
||||
"port": 8202,
|
||||
"interval_seconds": 300,
|
||||
"recursive": true,
|
||||
"recursive_depth": 4,
|
||||
"cache_update_minutes": 60,
|
||||
"ignore_repos": [
|
||||
".archive",
|
||||
"_archive",
|
||||
".deprecated"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"node_modules",
|
||||
"pyvenv",
|
||||
".venv",
|
||||
"venv",
|
||||
"dist",
|
||||
"build",
|
||||
"__pycache__"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
echo " ✓ startup-config.json created (3 daemons: packages, applications, projects)"
|
||||
|
||||
# =============================================================================
|
||||
# Step 4: Create systemd user services
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "==> Setting up systemd user services..."
|
||||
mkdir -p ~/.config/systemd/user
|
||||
|
||||
# Clean up old services
|
||||
echo " Cleaning up old services..."
|
||||
for svc in llama-http.service commits-*.service auto-commit-*.service; do
|
||||
systemctl --user stop "$svc" 2>/dev/null || true
|
||||
systemctl --user disable "$svc" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# Model Boss Coordinator
|
||||
cat > ~/.config/systemd/user/model-boss-coordinator.service << EOF
|
||||
[Unit]
|
||||
Description=Model Boss Coordinator (GPU/VRAM lease management)
|
||||
After=network.target
|
||||
Wants=homebrew.redis.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$COORDINATOR_PATH
|
||||
ExecStart=$COORDINATOR_PATH/.venv/bin/python -m model_boss_coordinator
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/var/home/lilith/.local/bin:/usr/local/bin:/usr/bin:/bin"
|
||||
Environment="HOME=/var/home/lilith"
|
||||
Environment="MODEL_BOSS_PORT=8210"
|
||||
Environment="MODEL_BOSS_HOST=0.0.0.0"
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
# Llama HTTP 3B (instruct/formatting)
|
||||
cat > ~/.config/systemd/user/llama-http-3b.service << EOF
|
||||
[Unit]
|
||||
Description=Llama HTTP Service - 3B (ministral-3b-instruct)
|
||||
After=network.target model-boss-coordinator.service
|
||||
Wants=model-boss-coordinator.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$LLAMA_HTTP_PATH
|
||||
ExecStart=$LLAMA_HTTP_PATH/.venv/bin/python -m llama_http
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/var/home/lilith/.local/bin:/usr/local/bin:/usr/bin:/bin"
|
||||
Environment="HOME=/var/home/lilith"
|
||||
Environment="LLAMA_HTTP_SERVICE_NAME=llama-http-3b"
|
||||
Environment="LLAMA_HTTP_PORT=10010"
|
||||
Environment="LLAMA_HTTP_MODEL_ID=ministral-3b-instruct"
|
||||
Environment="LLAMA_HTTP_CONTEXT_SIZE=4096"
|
||||
Environment="LLAMA_HTTP_N_GPU_LAYERS=-1"
|
||||
Environment="LLAMA_HTTP_LLAMA_SERVER_PORT=10009"
|
||||
Environment="LLAMA_HTTP_IDLE_TIMEOUT_SECONDS=0"
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
# Llama HTTP 14B (reasoning/analysis)
|
||||
cat > ~/.config/systemd/user/llama-http-14b.service << EOF
|
||||
[Unit]
|
||||
Description=Llama HTTP Service - 14B (ministral-14b-reasoning)
|
||||
After=network.target model-boss-coordinator.service
|
||||
Wants=model-boss-coordinator.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$LLAMA_HTTP_PATH
|
||||
ExecStart=$LLAMA_HTTP_PATH/.venv/bin/python -m llama_http
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/var/home/lilith/.local/bin:/usr/local/bin:/usr/bin:/bin"
|
||||
Environment="HOME=/var/home/lilith"
|
||||
Environment="LLAMA_HTTP_SERVICE_NAME=llama-http-14b"
|
||||
Environment="LLAMA_HTTP_PORT=10020"
|
||||
Environment="LLAMA_HTTP_MODEL_ID=ministral-14b-reasoning"
|
||||
Environment="LLAMA_HTTP_CONTEXT_SIZE=8192"
|
||||
Environment="LLAMA_HTTP_N_GPU_LAYERS=-1"
|
||||
Environment="LLAMA_HTTP_LLAMA_SERVER_PORT=10019"
|
||||
Environment="LLAMA_HTTP_IDLE_TIMEOUT_SECONDS=0"
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
# RAG Retrieval Service
|
||||
cat > ~/.config/systemd/user/rag-retrieval.service << EOF
|
||||
[Unit]
|
||||
Description=RAG Retrieval Service (vector search + context)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$RAG_PATH
|
||||
ExecStart=$RAG_PATH/.venv/bin/python -m service.src.api.main
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/var/home/lilith/.local/bin:/usr/local/bin:/usr/bin:/bin"
|
||||
Environment="HOME=/var/home/lilith"
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
# Auto-commit services (3 daemons for packages, applications, projects)
|
||||
for DAEMON_NAME in packages applications projects; do
|
||||
case $DAEMON_NAME in
|
||||
packages) WORK_DIR="/var/home/lilith/Code/@packages" ;;
|
||||
applications) WORK_DIR="/var/home/lilith/Code/@applications" ;;
|
||||
projects) WORK_DIR="/var/home/lilith/Code/@projects" ;;
|
||||
esac
|
||||
|
||||
cat > ~/.config/systemd/user/commits-${DAEMON_NAME}.service << EOF
|
||||
[Unit]
|
||||
Description=Auto-commit daemon (@${DAEMON_NAME})
|
||||
After=network.target llama-http-3b.service llama-http-14b.service rag-retrieval.service
|
||||
Wants=llama-http-3b.service llama-http-14b.service rag-retrieval.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=$WORK_DIR
|
||||
ExecStart=$SCRIPT_DIR/.venv/bin/python -m auto_commit_service
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/var/home/lilith/.local/bin:/usr/local/bin:/usr/bin:/bin"
|
||||
Environment="HOME=/var/home/lilith"
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
done
|
||||
|
||||
echo " ✓ systemd services created"
|
||||
|
||||
# =============================================================================
|
||||
# Step 5: Enable and start services
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "==> Reloading systemd..."
|
||||
systemctl --user daemon-reload
|
||||
|
||||
echo "==> Enabling services..."
|
||||
systemctl --user enable model-boss-coordinator.service
|
||||
systemctl --user enable llama-http-3b.service
|
||||
systemctl --user enable llama-http-14b.service
|
||||
systemctl --user enable rag-retrieval.service
|
||||
systemctl --user enable commits-packages.service
|
||||
systemctl --user enable commits-applications.service
|
||||
systemctl --user enable commits-projects.service
|
||||
|
||||
echo "==> Enabling lingering..."
|
||||
loginctl enable-linger "$(whoami)" 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "==> Starting services in dependency order..."
|
||||
|
||||
echo " [1/5] Starting model-boss-coordinator..."
|
||||
systemctl --user start model-boss-coordinator.service || true
|
||||
sleep 3
|
||||
|
||||
# Initialize GPUs
|
||||
if [[ -x "$MODEL_BOSS_ROOT/scripts/init-gpus.sh" ]]; then
|
||||
echo " [1.5/5] Initializing GPUs..."
|
||||
"$MODEL_BOSS_ROOT/scripts/init-gpus.sh" || true
|
||||
fi
|
||||
|
||||
echo " [2/5] Starting llama-http-3b..."
|
||||
systemctl --user start llama-http-3b.service || true
|
||||
|
||||
echo " [3/5] Starting llama-http-14b..."
|
||||
systemctl --user start llama-http-14b.service || true
|
||||
|
||||
echo " [4/5] Starting rag-retrieval..."
|
||||
systemctl --user start rag-retrieval.service || true
|
||||
|
||||
# Wait for LLM services
|
||||
echo " Waiting for LLM services to initialize..."
|
||||
MAX_WAIT=120
|
||||
WAITED=0
|
||||
while ! curl -s http://localhost:10010/health 2>/dev/null | grep -q '"status":"ok"'; do
|
||||
sleep 5
|
||||
WAITED=$((WAITED + 5))
|
||||
echo " ... waiting ($WAITED/${MAX_WAIT}s)"
|
||||
if [[ $WAITED -ge $MAX_WAIT ]]; then
|
||||
echo " WARNING: llama-http-3b not ready after ${MAX_WAIT}s"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
echo " [5/7] Starting commits-packages daemon..."
|
||||
systemctl --user start commits-packages.service || true
|
||||
|
||||
echo " [6/7] Starting commits-applications daemon..."
|
||||
systemctl --user start commits-applications.service || true
|
||||
|
||||
echo " [7/7] Starting commits-projects daemon..."
|
||||
systemctl --user start commits-projects.service || true
|
||||
|
||||
# =============================================================================
|
||||
# Summary
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Installation complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Services:"
|
||||
echo " model-boss-coordinator: http://localhost:8210"
|
||||
echo " llama-http-3b: http://localhost:10010 (ministral-3b-instruct)"
|
||||
echo " llama-http-14b: http://localhost:10020 (ministral-14b-reasoning)"
|
||||
echo " rag-retrieval: http://localhost:8111"
|
||||
echo " commits-packages: http://localhost:8200 (@packages)"
|
||||
echo " commits-applications: http://localhost:8201 (@applications)"
|
||||
echo " commits-projects: http://localhost:8202 (@projects)"
|
||||
echo ""
|
||||
echo "Config files:"
|
||||
echo " ~/.config/commits/startup-config.json"
|
||||
echo " ~/.config/commits/daemons.json (runtime)"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " commits status - Show daemon status"
|
||||
echo " commits list - List all daemons"
|
||||
echo " commits commit --dry-run - Preview commit"
|
||||
echo " journalctl --user -u commits -f - View logs"
|
||||
echo ""
|
||||
|
||||
# Show service status
|
||||
echo "==> Service status:"
|
||||
for svc in model-boss-coordinator llama-http-3b llama-http-14b rag-retrieval commits-packages commits-applications commits-projects; do
|
||||
STATUS=$(systemctl --user is-active ${svc}.service 2>/dev/null || echo "unknown")
|
||||
printf " %-25s %s\n" "$svc:" "$STATUS"
|
||||
done
|
||||
167
upgrade
Executable file
167
upgrade
Executable file
|
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Upgrade auto-commit-service and restart services
|
||||
# =============================================================================
|
||||
# This script:
|
||||
# 1. Stops the commits service
|
||||
# 2. Upgrades Python dependencies
|
||||
# 3. Ensures config files exist
|
||||
# 4. Reloads systemd and restarts services
|
||||
# 5. Records deployment for tracking
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
echo "==> Stopping commits service..."
|
||||
systemctl --user stop commits.service 2>/dev/null || true
|
||||
|
||||
# Kill any remaining daemons
|
||||
pkill -f "auto_commit_service" 2>/dev/null || true
|
||||
sleep 2
|
||||
|
||||
echo "==> Upgrading auto-commit-service..."
|
||||
pip install -e . --quiet --upgrade
|
||||
|
||||
echo "==> Ensuring model-boss coordinator is set up..."
|
||||
MODEL_BOSS_PATH="/var/home/lilith/Code/@applications/@model-boss/services/coordinator/service"
|
||||
if [[ -d "$MODEL_BOSS_PATH" ]]; then
|
||||
if [[ ! -d "$MODEL_BOSS_PATH/.venv" ]]; then
|
||||
echo " Creating model-boss-coordinator venv..."
|
||||
python -m venv "$MODEL_BOSS_PATH/.venv"
|
||||
fi
|
||||
echo " Installing model-boss-coordinator dependencies..."
|
||||
"$MODEL_BOSS_PATH/.venv/bin/pip" install -e "$MODEL_BOSS_PATH" --quiet 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "==> Ensuring config exists..."
|
||||
mkdir -p ~/.config/commits
|
||||
|
||||
# Create startup-config.json if it doesn't exist
|
||||
if [[ ! -f ~/.config/commits/startup-config.json ]]; then
|
||||
echo " Creating startup-config.json..."
|
||||
cat > ~/.config/commits/startup-config.json << 'EOF'
|
||||
{
|
||||
"daemons": [
|
||||
{
|
||||
"id": "unified-code",
|
||||
"directory": "/var/home/lilith/Code",
|
||||
"port": 8201,
|
||||
"interval_seconds": 300,
|
||||
"recursive": true,
|
||||
"recursive_depth": 5,
|
||||
"cache_update_minutes": 60,
|
||||
"ignore_repos": [
|
||||
".archive",
|
||||
"_archive",
|
||||
"egirl-platform",
|
||||
".deprecated"
|
||||
],
|
||||
"exclude_patterns": [
|
||||
"node_modules",
|
||||
"pyvenv",
|
||||
".venv",
|
||||
"venv",
|
||||
"dist",
|
||||
"build",
|
||||
"__pycache__"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "==> Ensuring systemd service is config-based..."
|
||||
# Update commits.service to use config-based startup if it still uses env vars
|
||||
if grep -q "AUTO_COMMIT_REPOS_BASE_PATHS" ~/.config/systemd/user/commits.service 2>/dev/null; then
|
||||
echo " Updating commits.service to config-based..."
|
||||
cat > ~/.config/systemd/user/commits.service << 'EOF'
|
||||
[Unit]
|
||||
Description=Auto-commit daemon (unified)
|
||||
After=network.target llama-http.service model-boss-coordinator.service
|
||||
Wants=llama-http.service model-boss-coordinator.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/var/home/lilith/Code
|
||||
ExecStart=/var/home/lilith/Code/@applications/@ml/auto-commit-service/.venv/bin/python -m auto_commit_service
|
||||
ExecStop=/var/home/lilith/.local/bin/commits stop
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
# Minimal env - config loaded from ~/.config/commits/startup-config.json
|
||||
Environment="PATH=/home/linuxbrew/.linuxbrew/bin:/var/home/lilith/.local/bin:/usr/local/bin:/usr/bin:/bin"
|
||||
Environment="HOME=/var/home/lilith"
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "==> Reloading systemd..."
|
||||
systemctl --user daemon-reload
|
||||
|
||||
echo "==> Starting service chain..."
|
||||
# Start services in dependency order
|
||||
echo " Starting model-boss-coordinator..."
|
||||
systemctl --user start model-boss-coordinator.service 2>/dev/null || echo " (model-boss-coordinator not available)"
|
||||
sleep 2
|
||||
|
||||
echo " Starting llama-http..."
|
||||
systemctl --user start llama-http.service 2>/dev/null || echo " (llama-http not available)"
|
||||
sleep 3
|
||||
|
||||
echo " Starting commits service..."
|
||||
systemctl --user start commits.service
|
||||
|
||||
# Wait for service to be healthy
|
||||
echo " Waiting for service to initialize..."
|
||||
sleep 5
|
||||
|
||||
# Get version info for deployment tracking
|
||||
VERSION=$(grep -oP 'version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "")
|
||||
COMMIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "")
|
||||
|
||||
# Get port from config
|
||||
DAEMON_PORT=$(jq -r '.daemons[0].port // 8201' ~/.config/commits/startup-config.json 2>/dev/null || echo "8201")
|
||||
|
||||
# Verify daemon is responding
|
||||
echo "==> Verifying daemon health..."
|
||||
for i in {1..5}; do
|
||||
if curl -s "http://localhost:$DAEMON_PORT/health" >/dev/null 2>&1; then
|
||||
echo " Daemon healthy on port $DAEMON_PORT"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Record the deployment
|
||||
echo "==> Recording deployment..."
|
||||
if curl -s "http://localhost:$DAEMON_PORT/health" >/dev/null 2>&1; then
|
||||
if [[ -n "$COMMIT_HASH" ]]; then
|
||||
commits mark-deployed -p "$DAEMON_PORT" -c "$COMMIT_HASH" ${VERSION:+-v "$VERSION"} -n "Upgrade via ./upgrade script" 2>/dev/null || echo " (deployment tracking not available)"
|
||||
else
|
||||
commits mark-deployed -p "$DAEMON_PORT" ${VERSION:+-v "$VERSION"} -n "Upgrade via ./upgrade script" 2>/dev/null || echo " (deployment tracking not available)"
|
||||
fi
|
||||
else
|
||||
echo " No running daemon found, skipping deployment recording"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "==> Upgrade complete!"
|
||||
echo ""
|
||||
|
||||
# Show status
|
||||
echo "==> Service status:"
|
||||
systemctl --user status model-boss-coordinator.service --no-pager 2>/dev/null | head -5 || true
|
||||
systemctl --user status llama-http.service --no-pager 2>/dev/null | head -5 || true
|
||||
systemctl --user status commits.service --no-pager 2>/dev/null | head -5 || true
|
||||
|
||||
echo ""
|
||||
commits list 2>/dev/null || echo "Run 'commits list' to see daemon status"
|
||||
echo ""
|
||||
echo "TIP: Run 'commits history' to see commits since the last deployment"
|
||||
Loading…
Add table
Reference in a new issue