https://github.com/grobomo/github-agent
Monitor GitHub activity across accounts — LLM-powered analysis with auto-response, alerting, and task dispatch
https://github.com/grobomo/github-agent
automation github llm monitoring sqlite
Last synced: 18 days ago
JSON representation
Monitor GitHub activity across accounts — LLM-powered analysis with auto-response, alerting, and task dispatch
- Host: GitHub
- URL: https://github.com/grobomo/github-agent
- Owner: grobomo
- License: mit
- Created: 2026-04-06T04:23:28.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-06T06:20:41.000Z (3 months ago)
- Last Synced: 2026-04-06T06:27:28.406Z (3 months ago)
- Topics: automation, github, llm, monitoring, sqlite
- Language: Python
- Size: 76.2 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GitHub Agent
Monitors all GitHub activity across multiple accounts. Polls issues, PRs, discussions, notifications, workflow runs, and settings changes. Uses LLM analysis (`claude -p`) with full historical context to decide actions: respond, dispatch tasks, send alerts, or log.
## How it works
```
GitHub API (via gh CLI)
│
▼
GitHubPoller (per-account, auto-discovers repos)
├── Issues, PRs, Discussions, Notifications
├── Repo events (pushes, forks, stars)
├── Workflow runs (failures)
└── Settings snapshots (drift detection)
│
▼
Normalizer → EventStore (SQLite + FTS)
│
▼
Brain (LLM analysis with three-tier memory)
│
▼
Dispatcher (comment via gh, dispatch to CCC, alert via email, log)
```
The brain classifies each event as one of:
| Action | Description |
|--------|-------------|
| **IGNORE** | Routine activity, no action needed |
| **LOG** | Interesting but not actionable — stored for context |
| **RESPOND** | Post a comment on the issue/PR/discussion |
| **DISPATCH** | Send a task to the CCC dispatcher for deeper work |
| **ALERT** | Email notification — something urgent or security-sensitive |
Security-sensitive events (visibility changes, branch protection removal, admin access grants, leaked secrets) always trigger ALERT.
## Quick start
```bash
# Prerequisites: gh CLI authenticated, Python 3.12+
pip install -r requirements.txt # optional: only pyyaml for config file support
# Single account, single poll, dry run
python main.py --account grobomo --once --dry-run -v
# Continuous monitoring (10s notification checks, 5min full scans)
python main.py --account grobomo --interval 10 --full-scan-interval 300
# With health endpoint
python main.py --account grobomo --interval 10 --health-port 8081
```
## Running as a service
```bash
# Install as continuous service (silent, no visible windows)
bash scripts/install-scheduler.sh --mode service
# Install as periodic task (every 5 min)
bash scripts/install-scheduler.sh
# Check status
bash scripts/install-scheduler.sh --status
# Remove
bash scripts/install-scheduler.sh --remove
# Check agent health (reads heartbeat file)
bash scripts/watchdog.sh
```
The service uses tiered polling: fast notification checks every 10 seconds, full repo scans every 5 minutes. A process guard prevents duplicate instances. On Windows, the service runs silently via VBS launcher (no cmd windows, no focus stealing).
### Health monitoring
The agent writes `data/heartbeat.json` after each poll cycle. The watchdog script (`scripts/watchdog.sh`) checks heartbeat freshness and kills stale processes. A circuit breaker (`--max-errors 50`) exits after consecutive errors to prevent infinite loops — the scheduled task restarts it on the next cycle.
Log rotation is built in: `--log-max-bytes 5000000 --log-backup-count 3` (defaults).
## Dashboard
Generate a self-contained HTML status page from the SQLite database:
```bash
# Generate report and open in browser
python main.py --account grobomo --report
# Custom output path
python main.py --account grobomo --report --output status.html
```
The dashboard includes:
- Agent status cards (total events, 24h activity, actions taken)
- Event volume chart (SVG bar chart, last 24h by hour)
- Recent events table with type badges
- Action history (responses, alerts, dispatches)
## Project structure
```
main.py # CLI entry point + agent loop
core/
store.py # EventStore — SQLite + FTS + WAL mode
brain.py # LLM analyzer + rule-based fallback
dispatcher.py # Action executor (gh comment, email, CCC)
context.py # Context cache for brain prompts (Tier 1)
memory.py # Per-repo + account memory (Tier 2/3)
compactor.py # LLM-based memory compaction
report.py # HTML dashboard report generator
github/
poller.py # GitHub API polling via gh CLI
normalizer.py # Raw API → EventStore records
settings.py # Settings snapshot + drift detection
gh_cli.py # gh CLI wrapper
scripts/
service.sh # Continuous service launcher (Linux/Git Bash)
service.bat # Continuous service launcher (Windows)
service-silent.vbs # Silent VBS launcher (no visible windows)
install-scheduler.sh # Install/remove OS scheduled task
watchdog.sh # Health check — heartbeat freshness monitor
run.sh # Run all accounts in parallel
tests/ # 90 tests covering all modules
```
## Design decisions
- **One process per account** — security isolation between accounts
- **SQLite WAL mode** — concurrent reads during polling, busy_timeout for resilience
- **Three-tier memory** — Tier 1: hot cache (24h events), Tier 2: per-repo JSON (purpose, milestones, threads), Tier 3: account-level summary. LLM compaction distills events into long-term context.
- **Rule-based fallback** — when `claude` CLI is unavailable, built-in rules handle common patterns (own pushes → IGNORE, security events → ALERT)
- **Settings drift detection** — snapshots repo settings each cycle, alerts on security-relevant changes with severity levels (critical/high/medium/low)
- **Service health** — heartbeat file, log rotation, watchdog script, circuit breaker for consecutive errors
- **Source-agnostic core** — `core/` knows nothing about GitHub specifically, designed for reuse by other agents (Teams, Slack, etc.)
## Configuration
Create `config/accounts.yaml` to define accounts:
```yaml
accounts:
grobomo:
repos: [] # empty = auto-discover all repos
another-account:
repos:
- owner/specific-repo
```
Or pass repos directly via CLI: `--repos owner/repo1 owner/repo2`
## License
MIT