Skip to content
ru logo

ru

Repo Updater - Multi-repo synchronization with AI-assisted review orchestration. Parallel sync, agent-sweep for dirty repos, ntm integration, git plumbing. 17K LOC Bash CLI.

SKILL.md

Full skill instructions

RU - Repo Updater

A comprehensive Bash CLI for synchronizing dozens or hundreds of GitHub repositories. Beyond basic sync, RU includes a full AI-assisted code review system and agent-sweep capability for automatically processing uncommitted changes across your entire projects directory.

Why This Exists

When you work with 47+ repos (personal projects, forks, dependencies), keeping them synchronized manually is tedious. But synchronization is just the beginning—RU also orchestrates AI coding agents to review issues, process PRs, and commit uncommitted work at scale.

The problem it solves:

  • Manual cd ~/​project && git pull for each repo
  • Missing updates that accumulate into merge conflicts
  • Dirty repos that never get committed
  • Issues and PRs that pile up across repositories
  • No coordination for AI agents working across repos

Critical Concepts

Git Plumbing, Not Porcelain

RU uses git plumbing commands exclusively—never parses human-readable output:

# WRONG: Locale-dependent, version-fragile
git pull 2>&1 | grep "Already up to date"

# RIGHT: Machine-readable plumbing
git rev-list --left-right --count HEAD...@{u}
git status --porcelain
git rev-parse HEAD

Stream Separation

Human-readable output goes to stderr; data to stdout:

ru sync --json 2>/​dev/​null | jq '.summary'
# Progress shows in terminal, JSON pipes to jq

No Global cd

All git operations use git -C. Never changes working directory.

Essential Commands

Sync (Primary Use Case)

# Sync all configured repos
ru sync

# Parallel sync (much faster)
ru sync -j8

# Dry run - see what would happen
ru sync --dry-run

# Resume interrupted sync
ru sync --resume

# JSON output for scripting
ru sync --json 2>/​dev/​null | jq '.summary'

Status (Read-Only Check)

# Check all repos without modifying
ru status

# JSON output
ru status --json

Repo Management

# Initialize configuration
ru init

# Add repos to sync list
ru add owner/​repo
ru add https://github.com/owner/repo
ru add owner/​repo@branch as custom-name

# Remove from list
ru remove owner/​repo

# List configured repos
ru list

# Detect orphaned repos (in projects dir but not in list)
ru prune           # Preview
ru prune --delete  # Actually remove
ru prune --archive # Move to archive directory

Diagnostics

ru doctor      # System health check
ru self-update # Update ru itself

AI-Assisted Review System

RU includes a powerful review orchestration system for managing AI-assisted code review across your repositories.

⚠️ CRITICAL SAFETY RULES - NEVER VIOLATE ⚠️

1. NEVER Stash User Changes If repositories have uncommitted changes, NEVER use git stash. This risks losing user work. Stashed changes can be difficult to recover, especially untracked files which require git show stash@{0}^3:path to extract.

2. NEVER Modify Working Tree Without Permission Do not run git checkout, git reset, git clean, or any command that modifies uncommitted changes without explicit user permission.

3. Commit Changes First (The Correct Approach) If repos have uncommitted changes and the user wants to proceed with review, commit the changes first with logical groupings and detailed messages, then push.

4. Let ru Skip Dirty Repos The ru review command automatically skips repositories with uncommitted changes. This is correct behavior—let it skip them rather than forcing them clean.

Decision Tree: Handling Dirty Repos

Found uncommitted changes in repos?
├── User wants to proceed with ru review?
│   ├── YES → Ask: "Should I commit these changes first?"
│   │   ├── User says YES → Commit with logical groupings, push, then run ru review
│   │   └── User says NO → Let ru skip those repos, review clean repos only
│   └── NO → Stop, let user handle their changes
└── No uncommitted changes → Run ru review normally

Two-Phase Review Workflow

Phase 1: Discovery (--plan)

  • Queries GitHub for open issues and PRs across all repos
  • Scores items by priority using label analysis and age
  • Creates isolated git worktrees for safe review
  • Spawns Claude Code sessions in terminal multiplexer

Phase 2: Application (--apply)

  • Reviews proposed changes from discovery phase
  • Runs quality gates (ShellCheck, tests, lint)
  • Optionally pushes approved changes (--push)
# Discovery - see what issues/​PRs exist
ru review --dry-run

# Plan mode - generate review plans, no mutations
ru review --plan

# After reviewing AI suggestions
ru review --apply --push

Priority Scoring Algorithm

FactorPointsLogic
Type0-20PRs: +20, Issues: +10, Draft PRs: -15
Labels0-50security/​critical: +50, bug/​urgent: +30
Age (bugs)0-50>60 days: +50, >30 days: +30
Recency0-15Updated <3 days: +15, <7 days: +10
Staleness-20Recently reviewed: -20

Priority levels: CRITICAL (≥150), HIGH (≥100), NORMAL (≥50), LOW (<50)

Session Drivers

DriverDescriptionBest For
autoAuto-detect best availableDefault
ntmNamed Tmux Manager integrationMulti-agent workflows
localDirect tmux sessionsSimple setups
ru review --mode=ntm --plan
ru review --mode=local --plan  # Use if ntm has issues
ru review -j 4 --plan          # Parallel sessions

Review Options

ru review --max-repos=10 --plan       # Limit repos
ru review --max-runtime=30 --plan     # Minutes budget
ru review --skip-days=14 --plan       # Skip recently reviewed
ru review --repos=PATTERN --plan      # Filter by regex
ru review --analytics                 # View past review stats

Contribution Policy

The ru review command includes this contribution policy in its prompts:

We don't allow PRs or outside contributions to this project as a matter of policy. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via gh and independently decide whether and how to address them.

Key principle: Independently verify and validate all user reports. Don't trust submitted fixes blindly—use them as inspiration but verify everything against actual code and documentation.

Multi-Agent Coordination

When multiple agents review repos simultaneously:

  1. Use alphabetical ordering - One agent works A→Z, another Z→A
  2. Check which repos are in progress - Look for uncommitted changes or lock files
  3. Skip repos being worked on - Don't review a repo another agent is actively modifying

Review Response Guidelines

When reviewing issues and PRs:

  • Verify independently - Don't trust submitted code blindly
  • Check actual behavior - Run tests, verify against docs
  • Use gh commands to respond on behalf of the user
  • Close issues that are resolved or invalid
  • Request clarification if issue is unclear

What NOT to Do During Review

  • ❌ git stash - NEVER stash user changes
  • ❌ git checkout -- . - NEVER discard changes
  • ❌ git reset --hard - NEVER reset working tree
  • ❌ git clean -fd - NEVER clean untracked files
  • ❌ Shell loops to iterate repos - ru handles iteration internally
  • ❌ Direct gh commands for bulk operations - use ru's orchestration

What TO Do During Review

  • ✅ Use ru review --dry-run to discover work items
  • ✅ Let ru skip repos with uncommitted changes
  • ✅ Ask user before modifying their working tree state
  • ✅ Commit changes (with user permission) before review if needed
  • ✅ Use --mode=local if ntm has issues
  • ✅ Work in reverse alphabetical order when coordinating with other agents

Emergency: Recovering from Accidental Stash

If someone accidentally stashed changes:

Tracked Files (Easy):

git stash pop  # Restore tracked changes

Untracked Files (Harder):

# List untracked files in stash
git show stash@{0}^3 --name-only

# Extract a specific untracked file
git show stash@{0}^3:path/​to/​file.rs > path/​to/​file.rs

If Stash Was Dropped:

# Find dangling stash commits
git fsck --unreachable | grep commit

# For each commit, check if it's your stash
git show <commit-hash>

# Recover if found
git stash apply <commit-hash>

Agent Sweep (Automated Dirty Repo Processing)

The ru agent-sweep command orchestrates AI coding agents to automatically process repositories with uncommitted changes.

Basic Usage

# Process all repos with uncommitted changes
ru agent-sweep

# Dry run - preview what would be processed
ru agent-sweep --dry-run

# Process 4 repos in parallel
ru agent-sweep -j4

# Filter to specific repos
ru agent-sweep --repos="myproject*"

# Include release step after commit
ru agent-sweep --with-release

# Resume interrupted sweep
ru agent-sweep --resume

# Start fresh
ru agent-sweep --restart

Three-Phase Agent Workflow

Phase 1: Planning (--phase1-timeout, default 300s)

  • Claude Code analyzes uncommitted changes
  • Determines which files should be staged (respecting denylist)
  • Generates structured commit message

Phase 2: Commit (--phase2-timeout, default 600s)

  • Validates the plan (file existence, denylist compliance)
  • Stages approved files, creates commit
  • Runs quality gates
  • Optionally pushes to remote

Phase 3: Release (--phase3-timeout, default 300s, requires --with-release)

  • Analyzes commit history since last tag
  • Determines version bump (patch/​minor/​major)
  • Creates git tag and optionally GitHub release

Execution Modes

--execution-mode=agent  # Full AI-driven workflow (default)
--execution-mode=plan   # Phase 1 only: generate plan, stop
--execution-mode=apply  # Phase 2+3: execute existing plan

Preflight Checks

Each repo is validated before spawning an agent:

CheckSkip Reason
Is git repositorynot_a_git_repo
Git email configuredgit_email_not_configured
Not a shallow cloneshallow_clone
No rebase in progressrebase_in_progress
No merge in progressmerge_in_progress
Not detached HEADdetached_HEAD
Has upstream branchno_upstream_branch
Not divergeddiverged_from_upstream

Security Guardrails

File Denylist - Never committed regardless of agent output:

CategoryPatterns
Secrets.env, *.pem, *.key, id_rsa*, credentials.json
Build artifactsnode_modules, __pycache__, dist, build, target
Logs/​temp*.log, *.tmp, *.swp, .DS_Store
IDE files.idea, .vscode, *.iml

Secret Scanning:

--secret-scan=none   # Disable
--secret-scan=warn   # Warn but continue (default)
--secret-scan=block  # Block push on detection

Exit Codes

CodeMeaning
0All repos processed successfully
1Some repos failed (agent error, timeout)
2Quality gate failures (secrets, tests)
3System error (ntm, tmux missing)
4Invalid arguments
5Interrupted (use --resume)

Configuration

XDG-Compliant Directory Structure

~/​.config/​ru/
├── config               # Main config file
└── repos.d/
    ├── public.list      # Public repos (one per line)
    └── private.list     # Private repos (gitignored)

~/​.local/​state/​ru/
├── logs/
│   └── YYYY-MM-DD/
├── agent-sweep/
│   ├── state.json
│   └── results.ndjson
└── review/
    ├── digests/
    └── results/

Repo List Format

# ~/​.config/​ru/​repos.d/​public.list
owner/​repo
another-owner/​another-repo@develop
private-org/​repo@main as local-name
https://github.com/owner/repo.git

Layout Modes

LayoutExample Path
flat/​data/​projects/​repo
owner-repo/​data/​projects/​owner_repo
full/​data/​projects/​github.com/​owner/​repo
ru config --set LAYOUT=owner-repo

Per-Repo Configuration

# ~/​.../​your-repo/​.ru-agent.yml
agent_sweep:
  enabled: true
  max_file_size: 5242880  # 5MB
  extra_context: "This is a Python project using FastAPI"
  pre_hook: "make lint"
  post_hook: "make test"
  denylist_extra:
    - "*.backup"
    - "internal/​*"

ntm Integration

When ntm (Named Tmux Manager) is available, RU uses its robot mode API:

FunctionPurpose
ntm --robot-spawnCreate Claude Code session in new tmux pane
ntm --robot-sendSend prompts with chunking for long messages
ntm --robot-waitBlock until session completes with timeout
ntm --robot-activityQuery real-time session state
ntm --robot-statusGet status of all managed sessions
ntm --robot-interruptSend Ctrl+C to interrupt long operations

Output Modes

JSON Mode (--json)

ru sync --json 2>/​dev/​null
{
  "version": "1.2.0",
  "timestamp": "2025-01-03T14:30:00Z",
  "summary": {
    "total": 47,
    "cloned": 8,
    "updated": 34,
    "current": 3,
    "conflicts": 2
  },
  "repos": [...]
}

NDJSON Results Logging

{"repo":"mcp_agent_mail","action":"pull","status":"updated","duration":2}
{"repo":"beads_viewer","action":"clone","status":"cloned","duration":5}

jq Examples

# Get paths of all cloned repos
ru sync --json 2>/​dev/​null | jq -r '.repos[] | select(.action=="clone") | .path'

# Count by status
cat ~/​.local/​state/​ru/​logs/​latest/​results.ndjson | jq -s 'group_by(.status) | map({status: .[0].status, count: length})'

Update Strategies

ru sync                        # Default: ff-only (safest)
ru sync --rebase               # Rebase local commits
ru sync --autostash            # Auto-stash before pull
ru sync --force                # Force update (use with caution)
StrategyBehavior
ff-onlyFast-forward only; fails if diverged
rebaseRebase local commits on top of remote
mergeCreate merge commit if needed

Quality Gates

Before applying changes, RU runs automated quality gates:

Auto-detection by project type:

Project TypeTest CommandLint Command
npm/​yarnnpm testnpm run lint
Cargo (Rust)cargo testcargo clippy
Gogo test ./​...golangci-lint run
Pythonpytestruff check
Makefilemake testmake lint
Shell scripts(none)shellcheck *.sh

Rate Limiting

RU includes an adaptive parallelism governor:

ConditionAction
GitHub remaining < 100Reduce parallelism to 1
GitHub remaining < 500Reduce parallelism by 50%
Model 429 detectedPause new sessions for 60s
Error rate > 50%Open circuit breaker

Exit Codes (Sync)

CodeMeaning
0Success - all repos synced or current
1Partial failure - some repos failed
2Conflicts exist
3Dependency error (gh missing, auth failed)
4Invalid arguments
5Interrupted (use --resume)

Environment Variables

VariableDescriptionDefault
RU_PROJECTS_DIRBase directory for repos/​data/​projects
RU_LAYOUTPath layoutflat
RU_PARALLELParallel workers1
RU_TIMEOUTNetwork timeout (seconds)30
RU_UPDATE_STRATEGYPull strategyff-only
GH_TOKENGitHub token(from gh CLI)

Troubleshooting

Common Issues

IssueFix
gh: command not foundbrew install gh && gh auth login
gh: auth requiredgh auth login or set GH_TOKEN
Cannot fast-forwardUse --rebase or push first
dirty working treeCommit changes or use --autostash
diverged_from_upstreamgit fetch && git rebase origin/​main

Debug Mode

# View latest run log
cat ~/​.local/​state/​ru/​logs/​latest/​run.log

# View specific repo log
cat ~/​.local/​state/​ru/​logs/​latest/​repos/​mcp_agent_mail.log

# Run with verbose output
ru agent-sweep --verbose --debug

Preflight Failure Debugging

# View why repos were skipped
ru agent-sweep --json 2>/​dev/​null | jq '.repos[] | select(.status == "skipped")'

Installation

# One-liner
curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/repo_updater/main/install.sh | bash

# Verify
ru doctor

Architecture Notes

  • ~17,700 LOC pure Bash, no external dependencies beyond git, curl, gh
  • Work-stealing queue for parallel sync with atomic dequeue
  • Portable locking via mkdir (works on all POSIX systems)
  • Path security validation prevents traversal attacks
  • Retry with exponential backoff for network operations

Integration with Flywheel

ToolIntegration
Agent MailNotify agents when repos are updated; coordinate reviews
BVTrack repo sync as recurring beads
CASSSearch past sync sessions and agent-sweep logs
NTMRobot mode API for session orchestration
DCGRU runs inside DCG sandbox protection