diff --git a/README.md b/README.md index bc8d980a..5e518530 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,15 @@ timmy-config/ └── cron/ ← Cron job definitions ``` -## Important: No Loop Scripts Here +## Orchestration: Huey -All agent loop scripts (claude-loop.sh, gemini-loop.sh, etc.) have been **removed**. -They are replaced by [sovereign-orchestration](https://143.198.27.163:3000/Timmy_Foundation/sovereign-orchestration) — a single Python process with SQLite task queue. +All orchestration (triage, PR review, dispatch) runs via [Huey](https://github.com/coleifer/huey) with SQLite. +`orchestration.py` (6 lines) + `tasks.py` (~70 lines) replace the entire sovereign-orchestration repo (3,846 lines). -See DEPRECATED.md for details. +```bash +pip install huey +huey_consumer.py tasks.huey -w 2 -k thread +``` ## Deploy diff --git a/config.yaml b/config.yaml index 351f1839..1dcd03fd 100644 --- a/config.yaml +++ b/config.yaml @@ -226,11 +226,6 @@ providers: # provider: openrouter # model: google/gemini-2.5-flash -# Sovereign Orchestration MCP Server -# Exposes: Gitea API, Task Queue, Playbook Engine -mcp_servers: - orchestration: - command: "/Users/apayne/.hermes/hermes-agent/venv/bin/python3" - args: ["/Users/apayne/.hermes/hermes-agent/tools/orchestration_mcp_server.py"] - env: {} - timeout: 120 +# Orchestration: Huey (replaces sovereign-orchestration repo) +# Start with: huey_consumer.py timmy-config.tasks.huey +# See orchestration.py + tasks.py diff --git a/orchestration.py b/orchestration.py new file mode 100644 index 00000000..aeb5129d --- /dev/null +++ b/orchestration.py @@ -0,0 +1,6 @@ +"""Sovereign orchestration — Huey replaces 3,843 lines of homebrew.""" + +from huey import SqliteHuey, crontab +from pathlib import Path + +huey = SqliteHuey(filename=str(Path.home() / ".hermes" / "orchestration.db")) diff --git a/tasks.py b/tasks.py new file mode 100644 index 00000000..e222f9cb --- /dev/null +++ b/tasks.py @@ -0,0 +1,71 @@ +"""Timmy's scheduled work — triage, PR review, dispatch.""" + +from orchestration import huey +from huey import crontab + +# Import the Gitea client we already own +import sys; sys.path.insert(0, str(__import__('pathlib').Path.home() / '.hermes' / 'hermes-agent')) +from tools.gitea_client import GiteaClient + +REPOS = [ + "Timmy_Foundation/the-nexus", + "Timmy_Foundation/autolora", + "Timmy_Foundation/timmy-config", +] +NET_LINE_LIMIT = 10 + + +@huey.periodic_task(crontab(minute='*/15')) +def triage_issues(): + """Score and assign unassigned issues across all repos.""" + g = GiteaClient() + for repo in REPOS: + for issue in g.find_unassigned_issues(repo, limit=10): + g.create_comment(repo, issue.number, "🔍 Triaged by Huey — needs assignment.") + + +@huey.periodic_task(crontab(minute='*/30')) +def review_prs(): + """Review open PRs: check net diff, reject violations, merge clean ones.""" + g = GiteaClient() + for repo in REPOS: + for pr in g.list_pulls(repo, state="open", limit=20): + files = g.get_pull_files(repo, pr.number) + net = sum(f.additions - f.deletions for f in files) + if net > NET_LINE_LIMIT: + g.create_comment( + repo, pr.number, + f"❌ Net +{net} lines exceeds the {NET_LINE_LIMIT}-line limit. " + f"Find {net - NET_LINE_LIMIT} lines to cut. See CONTRIBUTING.md." + ) + continue + if pr.user.login == pr.head_repo: # self-merge guard placeholder + continue + # Clean PR — could auto-merge here when CI gate exists + + +@huey.periodic_task(crontab(minute='*/10')) +def dispatch_assigned(): + """Pick up issues assigned to agents and dispatch work.""" + g = GiteaClient() + agents = ["claude", "gemini", "kimi", "grok", "perplexity"] + for repo in REPOS: + for agent in agents: + issues = g.find_agent_issues(repo, agent, limit=5) + for issue in issues: + if any(c.body and "dispatched" in c.body.lower() + for c in g.list_comments(repo, issue.number, limit=5)): + continue # Already dispatched + dispatch_work.schedule((repo, issue.number, agent), delay=0) + + +@huey.task(retries=3, retry_delay=60) +def dispatch_work(repo, issue_number, agent): + """Dispatch a single issue to an agent. Huey handles retry.""" + g = GiteaClient() + issue = g.get_issue(repo, issue_number) + g.create_comment( + repo, issue_number, + f"⚡ Dispatched to `{agent}`. Huey task queued with retry." + ) + # Agent execution happens via hermes harness — this is the bridge