
Ru
- 2 installs
- 105 repo stars
- Updated July 24, 2026
- dicklesworthstone/repo_updater
Synchronizes dozens of GitHub repos in parallel and orchestrates AI agents to review issues, process PRs, and commit dirty repos at scale.
About
A Bash CLI that syncs many repositories using git plumbing and adds an AI-assisted review and agent-sweep system for processing uncommitted changes. A developer uses it to keep many repos current and coordinate agent reviews across them.
- Parallel `ru sync` plus agent-sweep with a secret denylist and quality gates
- Strict safety rules: never stash or reset a user's working tree
Ru by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,139 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dicklesworthstone/repo_updater --skill ruAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 105 |
| Last updated | July 24, 2026 |
| Repository | dicklesworthstone/repo_updater ↗ |
What it does
Synchronizes dozens of GitHub repos in parallel and orchestrates AI agents to review issues, process PRs, and commit dirty repos at scale.
Files
ru review - GitHub Issues/PRs Review Process
Overview
The ru (Repo Updater) CLI has a built-in ru review command that reviews GitHub issues and PRs across all configured repositories using Claude. It includes the project's contribution policy automatically.
⚠️ CRITICAL RULES - NEVER VIOLATE THESE ⚠️
1. NEVER Stash User Changes
If repositories have uncommitted changes, NEVER use `git stash`. This risks losing user work and is extremely dangerous. 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 State 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. Use this exact approach:
Now, based on your knowledge of the project, commit all changed files now in a series of logically connected groupings with super detailed commit messages for each and then push. Take your time to do it right. Don't edit the code at all. Don't commit obviously ephemeral files. Use ultrathink.How to group commits logically:
- Group by feature/subsystem (e.g., all sync-related files together)
- Group by type of change (e.g., all test files together if they test one feature)
- Keep config/infrastructure changes separate from feature changes
- Use clear commit message format:
feat(scope): descriptionorfix(scope): description
Skip ephemeral files (do NOT commit):
target/,target_*/- Rust build directoriesnode_modules/,web/node_modules/- npm packages*.pyc,__pycache__/- Python bytecodeplaywright-report/,test-results/- Test artifacts.coverage,htmlcov/- Coverage reports*.logfiles
4. Skip Dirty Repos - ru Handles This
The ru review command automatically skips repositories with uncommitted changes. This is the correct behavior. Let it skip them rather than trying to force 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 normallyHow ru review Works
Discovery Phase
ru review --dry-run # See what issues/PRs exist without starting sessionsPlan Mode (Default)
ru review --plan # Generate review plans, no mutationsApply Mode
ru review --apply # Execute approved plans from previous --plan runKey Options
--mode=local- Use local Claude instead of ntm--max-repos=N- Limit number of repos to review--repos=PATTERN- Filter repos by pattern (regex)--skip-days=N- Skip repos reviewed within N days--parallel=N- Concurrent review sessions (default: 4)--push- Allow pushing changes (with --apply)
⚠️ ABSOLUTE RULE: WE DO NOT MERGE PRs - EVER ⚠️
WE. DO. NOT. MERGE.
We don't allow PRs or outside contributions to any of these projects as a matter of policy. Here is the policy disclosed to users:
About Contributions: Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. 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. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.What This Means In Practice
1. NEVER run `gh pr merge` - Not ever. Not for any reason. 2. NEVER recommend merging a PR - Don't even suggest it. 3. PRs are for INSPIRATION ONLY - You can look at them to see if they contain good ideas. 4. Even good ideas need approval - Check with the user first before integrating even ideas from PRs, as they could take the project in an unwanted direction or introduce scope creep. 5. Implement fixes YOURSELF - If a PR or issue identifies a real problem, write your own fix from scratch after independent verification.
Independent Verification Protocol
When reviewing issues and PRs: 1. Do NOT trust user reports - They may be wrong, outdated, or misguided. 2. Do NOT trust proposed fixes - They may introduce bugs, security issues, or scope creep. 3. Check dates - Many issues may already be fixed by subsequent commits. 4. Verify against actual code - Read the current codebase, not what the user claims. 5. Test empirically - Run the code, check behavior, verify claims. 6. Use official documentation - Not user interpretations. 7. Write your own implementation - Even if inspired by a PR, the code must come from your own understanding.
After Review Actions
Use gh to respond on behalf of the owner:
- Close issues that are already fixed or invalid
- Comment on issues to acknowledge valid bugs (then fix them yourself)
- Comment on PRs to thank contributors but explain the no-merge policy
- Close PRs after extracting any useful information (if applicable)
Coordinating with Other Agents
When multiple agents are reviewing repos simultaneously:
1. Use alphabetical ordering - One agent works forward (A→Z), another works reverse (Z→A) 2. Check which repos are already in progress - Look for uncommitted changes or lock files 3. Skip repos being worked on - Don't try to review a repo another agent is actively modifying
Example: If another agent is working on beads_viewer, start from xf and work backwards through wasm_cmaes, ultrasearch, etc.
Typical Workflow
1. Check what needs review
ru review --dry-run2. Start plan-mode review
ru review --plan --mode=local3. If repos have uncommitted changes:
- Let ru skip them automatically
- OR ask user if they want to commit changes first
- NEVER stash or discard changes
4. After review plans are approved:
ru review --apply --pushTroubleshooting
"Repository has uncommitted changes"
This is normal and expected. Options:
- Let ru skip those repos (recommended)
- Ask user to commit their changes first
- Wait for other agents to finish their work
"Failed to prepare worktrees"
This often means some repos were skipped due to uncommitted changes but others succeeded. The review will still run on the successfully prepared repos.
Checkpoint Issues
If you see "Invalid JSON, refusing to write checkpoint":
rm -f ~/.local/state/ru/review/review-checkpoint.jsonWhat NOT to Do
- ❌
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
ghcommands for bulk operations - use ru's orchestration
What TO Do
- ✅ Use
ru review --dry-runto 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=localif ntm has issues - ✅ Work in reverse alphabetical order when coordinating with other agents
Emergency: Recovering from Accidental Stash
If someone accidentally stashed changes, here's how to recover:
Tracked Files (Easy)
git stash pop # Restore tracked changesUntracked Files (Harder - requires extraction)
Untracked files in a stash are stored in the third parent commit. To recover:
# 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.rsIf 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>Example: Complete Review Session
# 1. Discovery - see what needs review
ru review --dry-run
# 2. Check for dirty repos
for repo in /data/projects/*/; do
(cd "$repo" && [ -n "$(git status --porcelain)" ] && echo "$repo has changes")
done
# 3. If dirty repos exist, commit them first (with user permission)
# Use logical groupings, detailed messages, push each repo
# 4. Run the review
ru review --plan --mode=local
# 5. After plans approved
ru review --apply --pushReview Response Guidelines
When reviewing issues and PRs, remember:
- 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
⚠️ IMPORTANT: Check Twitter Before Responding on Behalf of Jeffrey
When the repo owner is Jeffrey Emanuel (GitHub: Dicklesworthstone, X/Twitter: @doodlestein), you MUST check his recent Twitter posts before giving advice or making statements in his name on topics he may have publicly discussed.
Why This Matters
Jeffrey has public opinions on many technical topics. Responses on his behalf should be consistent with his stated positions. Checking Twitter ensures you don't contradict something he's already said publicly.
How to Check Twitter
Use the xf tool to search his Twitter archive:
# Search for relevant tweets on a topic
xf search "contribution policy" --limit 10
# Search for opinions on specific tech
xf search "local LLM" --limit 10
# Search recent tweets (within last N days)
xf search "openrouter" --since "90 days ago" --limit 10The Twitter data is indexed at /data/projects/my_twitter_data and accessible via xf.
When to Check
- Before responding to feature requests (check if he's discussed the feature)
- Before explaining project philosophy (check his stated positions)
- Before declining/accepting approaches (check if he's opined on similar)
- Before discussing tools, frameworks, or tech choices
Example Workflow
# User asks about OpenRouter support
xf search "openrouter" --limit 5
# User asks about contribution policy
xf search "contribution" --limit 5
xf search "pull request" --limit 5
# User asks about local models
xf search "local model" --limit 5
xf search "ollama" --limit 5If you find relevant tweets, incorporate his stated position into your response. If no relevant tweets exist, proceed with your best judgment based on project context.
# SQLite databases
*.db
*.db?*
*.db-journal
*.db-wal
*.db-shm
# Daemon runtime files
daemon.lock
daemon.log
daemon.pid
bd.sock
# Sync runtime/backoff state (created/removed by bd sync)
sync-state.json
# Local version tracking (prevents upgrade notification spam after git ops)
.local_version
# Legacy database files
db.sqlite
bd.db
# Merge artifacts (temporary files from 3-way merge)
beads.base.jsonl
beads.base.meta.json
beads.left.jsonl
beads.left.meta.json
beads.right.jsonl
beads.right.meta.json
# Keep JSONL exports and config (source of truth for git)
!issues.jsonl
!metadata.json
!config.json
# bv (beads viewer) lock file
.bv.lock
# Local history backups
.br_history/
# Beads Configuration File
# This file configures default behavior for all bd commands in this repository
# All settings can also be set via environment variables (BD_* prefix)
# or overridden with command-line flags
# Issue prefix for this repository (used by bd init)
# If not set, bd init will auto-detect from directory name
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
# issue-prefix: ""
# Use no-db mode: load from JSONL, no SQLite, write back after each command
# When true, bd will use .beads/issues.jsonl as the source of truth
# instead of SQLite database
# no-db: false
# Disable daemon for RPC communication (forces direct database access)
# no-daemon: false
# Disable auto-flush of database to JSONL after mutations
# no-auto-flush: false
# Disable auto-import from JSONL when it's newer than database
# no-auto-import: false
# Enable JSON output by default
# json: false
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
# actor: ""
# Path to database (overridden by BEADS_DB or --db)
# db: ""
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
# auto-start-daemon: true
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
# flush-debounce: "5s"
# Git branch for beads commits (bd sync will commit to this branch)
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
# This setting persists across clones (unlike database config which is gitignored).
# Can also use BEADS_SYNC_BRANCH env var for local override.
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
# sync-branch: "beads-sync"
# Multi-repo configuration (experimental - bd-307)
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
# repos:
# primary: "." # Primary repo (where this database lives)
# additional: # Additional repos to hydrate from (read-only)
# - ~/beads-planning # Personal planning repo
# - ~/work-planning # Work planning repo
# Integration settings (access with 'bd config get/set')
# These are stored in the database, not in this file:
# - jira.url
# - jira.project
# - linear.url
# - linear.api-key
# - github.org
# - github.repo
{
"database": "beads.db",
"jsonl_export": "beads.jsonl"
}Beads - AI-Native Issue Tracking
Welcome to Beads! This repository uses Beads for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
What is Beads?
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
Learn more: github.com/steveyegge/beads
Quick Start
Essential Commands
# Create new issues
bd create "Add user authentication"
# View all issues
bd list
# View issue details
bd show <issue-id>
# Update issue status
bd update <issue-id> --status in_progress
bd update <issue-id> --status done
# Sync with git remote
bd syncWorking with Issues
Issues in Beads are:
- Git-native: Stored in
.beads/issues.jsonland synced like code - AI-friendly: CLI-first design works perfectly with AI coding agents
- Branch-aware: Issues can follow your branch workflow
- Always in sync: Auto-syncs with your commits
Why Beads?
✨ AI-Native Design
- Built specifically for AI-assisted development workflows
- CLI-first interface works seamlessly with AI coding agents
- No context switching to web UIs
🚀 Developer Focused
- Issues live in your repo, right next to your code
- Works offline, syncs when you push
- Fast, lightweight, and stays out of your way
🔧 Git Integration
- Automatic sync with git commits
- Branch-aware issue tracking
- Intelligent JSONL merge resolution
Get Started with Beads
Try Beads in your own projects:
# Install Beads
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
# Initialize in your repo
bd init
# Create your first issue
bd create "Try out Beads"Learn More
- Documentation: github.com/steveyegge/beads/docs
- Quick Start Guide: Run
bd quickstart - Examples: github.com/steveyegge/beads/examples
---
Beads: Issue tracking that moves at the speed of thought ⚡
# Use bd merge for beads JSONL files
.beads/issues.jsonl merge=beads
# Dependabot configuration for GitHub Actions
# Keeps action versions up to date with security patches and improvements
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
commit-message:
prefix: "ci"
labels:
- "dependencies"
- "github-actions"
reviewers:
- "Dicklesworthstone"
Note: This project does not merge external pull requests. PRs are reviewed as reference material and may inspire independent reimplementation. See CONTRIBUTING.md for details.
If you're reporting a bug, please open an Issue instead.
---
Description
<!-- What does this PR do? -->
Motivation
<!-- Why is this change needed? -->
# CI Workflow for repo_updater (ru)
# Runs on every push and PR to main
#
# Security: Uses minimal permissions and pinned action versions
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
# Cancel in-progress runs for the same branch/PR
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Minimal permissions - read-only access to repository contents
permissions:
contents: read
jobs:
shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@2.0.0
with:
scandir: '.'
severity: warning
additional_files: 'ru install.sh'
syntax:
name: Bash Syntax
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check ru syntax
run: bash -n ru
- name: Check install.sh syntax
run: bash -n install.sh
- name: Check test scripts syntax
run: |
for script in scripts/*.sh; do
echo "Checking syntax: $script"
bash -n "$script"
done
tests:
name: Test Suite (${{ matrix.os }})
needs: [shellcheck, syntax]
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Homebrew cache (macOS)
if: runner.os == 'macOS'
uses: actions/cache@v4
with:
path: |
~/Library/Caches/Homebrew
/usr/local/Cellar/bash
/opt/homebrew/Cellar/bash
key: ${{ runner.os }}-homebrew-bash-${{ hashFiles('.github/workflows/ci.yml') }}
restore-keys: |
${{ runner.os }}-homebrew-bash-
- name: Install bash 5 (macOS)
if: runner.os == 'macOS'
run: |
# Update brew and handle any stale cache issues
brew update || true
# Uninstall if present to avoid cache conflicts, then install fresh
brew uninstall --ignore-dependencies bash 2>/dev/null || true
brew install bash
# Link bash to ensure it's available in PATH (may already be linked)
brew link --overwrite bash 2>/dev/null || true
# Find the bash 5 binary - use formula prefix which is architecture-aware
BASH_5="$(brew --prefix bash)/bin/bash"
if [[ ! -x "$BASH_5" ]]; then
# Fallback to Homebrew prefix
BASH_5="$(brew --prefix)/bin/bash"
fi
if [[ ! -x "$BASH_5" ]]; then
# Last resort: search in Cellar
CELLAR="$(brew --cellar bash)"
BASH_5="$(ls -1 "$CELLAR"/*/bin/bash 2>/dev/null | tail -1)"
fi
if [[ -x "$BASH_5" ]]; then
echo "Found bash at: $BASH_5"
"$BASH_5" --version | head -1
echo "BASH_5=$BASH_5" >> $GITHUB_ENV
# Prepend to PATH so it takes precedence
echo "$(dirname "$BASH_5")" >> $GITHUB_PATH
else
echo "::error::Unable to locate Homebrew bash"
exit 1
fi
- name: Show bash version
if: runner.os == 'macOS'
run: |
echo "PATH: $PATH"
echo "BASH_5: $BASH_5"
"$BASH_5" --version | head -1
- name: Create test output directory
run: mkdir -p test-results
- name: Run all tests (TAP format)
id: tap_tests
run: |
if [[ "$(uname)" == "Darwin" ]]; then
"$BASH_5" ./scripts/run_all_tests.sh --tap 2>&1 | tee test-results/tests.tap
else
./scripts/run_all_tests.sh --tap 2>&1 | tee test-results/tests.tap
fi
- name: Run all tests (human-readable)
if: failure() || success()
run: |
if [[ "$(uname)" == "Darwin" ]]; then
"$BASH_5" ./scripts/run_all_tests.sh 2>&1 | tee test-results/tests.log
else
./scripts/run_all_tests.sh 2>&1 | tee test-results/tests.log
fi
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-${{ matrix.os }}
path: test-results/
retention-days: 14
install-test:
name: Installation Test
needs: [shellcheck, syntax]
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Homebrew cache (macOS)
if: runner.os == 'macOS'
uses: actions/cache@v4
with:
path: |
~/Library/Caches/Homebrew
/usr/local/Cellar/bash
/opt/homebrew/Cellar/bash
key: ${{ runner.os }}-homebrew-bash-${{ hashFiles('.github/workflows/ci.yml') }}
restore-keys: |
${{ runner.os }}-homebrew-bash-
- name: Install bash 5 (macOS)
if: runner.os == 'macOS'
run: |
# Update brew and handle any stale cache issues
brew update || true
# Uninstall if present to avoid cache conflicts, then install fresh
brew uninstall --ignore-dependencies bash 2>/dev/null || true
brew install bash
# Link bash to ensure it's available in PATH (may already be linked)
brew link --overwrite bash 2>/dev/null || true
# Find the bash 5 binary - use formula prefix which is architecture-aware
BASH_5="$(brew --prefix bash)/bin/bash"
if [[ ! -x "$BASH_5" ]]; then
# Fallback to Homebrew prefix
BASH_5="$(brew --prefix)/bin/bash"
fi
if [[ ! -x "$BASH_5" ]]; then
# Last resort: search in Cellar
CELLAR="$(brew --cellar bash)"
BASH_5="$(ls -1 "$CELLAR"/*/bin/bash 2>/dev/null | tail -1)"
fi
if [[ -x "$BASH_5" ]]; then
echo "Found bash at: $BASH_5"
"$BASH_5" --version | head -1
echo "BASH_5=$BASH_5" >> $GITHUB_ENV
# Prepend to PATH so it takes precedence
echo "$(dirname "$BASH_5")" >> $GITHUB_PATH
else
echo "::error::Unable to locate Homebrew bash"
exit 1
fi
- name: Run installer
run: |
chmod +x install.sh
# Use RU_UNSAFE_MAIN=1 to test main-branch install path
# (avoids dependency on GitHub releases existing)
RU_UNSAFE_MAIN=1 DEST=/tmp/ru-test ./install.sh
- name: Verify installation
run: |
test -x /tmp/ru-test/ru
echo "ru is installed and executable"
- name: Check version output
run: |
# Use brew bash on macOS since ru requires bash >= 4.3
if [[ "$(uname)" == "Darwin" ]]; then
"$BASH_5" /tmp/ru-test/ru --version
else
/tmp/ru-test/ru --version
fi
- name: Check help output
run: |
if [[ "$(uname)" == "Darwin" ]]; then
"$BASH_5" /tmp/ru-test/ru --help | head -20
else
/tmp/ru-test/ru --help | head -20
fi
version-check:
name: Version Consistency
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check VERSION file exists
run: |
if [[ ! -f VERSION ]]; then
echo "::warning::VERSION file not found"
exit 0
fi
- name: Verify version matches
run: |
if [[ ! -f VERSION ]]; then
exit 0
fi
file_version=$(cat VERSION)
script_version=$(grep -m1 'VERSION=' ru | cut -d'"' -f2)
if [[ "$file_version" != "$script_version" ]]; then
echo "::error::VERSION file ($file_version) does not match ru script ($script_version)"
exit 1
fi
echo "Versions are consistent: $file_version"
# installer-notify.yml
# Copy this to .github/workflows/ in your project
# Notifies ACFS when install.sh changes
#
# Setup:
# 1. Create a GitHub PAT with `repo` scope
# 2. Add it as ACFS_DISPATCH_TOKEN secret in your repo
# 3. Copy this file to .github/workflows/
name: Notify ACFS of Installer Change
on:
push:
branches: [main, master]
paths:
- 'install.sh'
- 'scripts/install.sh'
- '**/install.sh'
pull_request:
branches: [main, master]
paths:
- 'install.sh'
- 'scripts/install.sh'
- '**/install.sh'
concurrency:
group: installer-notify-${{ github.ref }}
cancel-in-progress: true
jobs:
notify-acfs:
# Only notify on push to main, not PRs
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Compute installer SHA256
id: checksum
run: |
# Find the installer file
if [ -f install.sh ]; then
INSTALLER_PATH="install.sh"
elif [ -f scripts/install.sh ]; then
INSTALLER_PATH="scripts/install.sh"
else
echo "No installer found"
exit 1
fi
SHA256=$(sha256sum "$INSTALLER_PATH" | cut -d' ' -f1)
echo "sha256=$SHA256" >> $GITHUB_OUTPUT
echo "Computed SHA256: $SHA256"
- name: Notify ACFS
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.ACFS_DISPATCH_TOKEN }}
repository: Dicklesworthstone/agentic_coding_flywheel_setup
event-type: installer-updated
client-payload: |
{
"tool": "${{ github.event.repository.name }}",
"repo": "${{ github.repository }}",
"commit": "${{ github.sha }}",
"new_sha256": "${{ steps.checksum.outputs.sha256 }}",
"ref": "${{ github.ref }}",
"actor": "${{ github.actor }}"
}
- name: Log notification
run: |
echo "::notice::Notified ACFS about installer change"
echo "Repository: ${{ github.repository }}"
echo "Commit: ${{ github.sha }}"
echo "SHA256: ${{ steps.checksum.outputs.sha256 }}"
# Validate installer syntax on PRs
validate-installer:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install shellcheck
run: sudo apt-get update && sudo apt-get install -y shellcheck
- name: Shellcheck installer
run: |
EXIT_CODE=0
for script in install.sh scripts/install.sh; do
if [ -f "$script" ]; then
echo "Checking $script..."
shellcheck "$script" || EXIT_CODE=1
fi
done
exit $EXIT_CODE
# Release Workflow for repo_updater (ru)
# Triggered by version tags (v*)
#
# Creates GitHub releases with checksums and notifies downstream package managers
name: Release
on:
push:
tags:
- 'v*'
# Only write permission needed for creating releases
permissions:
contents: write
# Prevent concurrent releases
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
release:
name: Create Release with Checksums
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Extract version from tag
id: version
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Releasing version: $VERSION"
- name: Verify script version matches tag
run: |
script_version=$(grep -m1 'VERSION=' ru | cut -d'"' -f2)
tag_version="${{ steps.version.outputs.version }}"
if [[ "$script_version" != "$tag_version" ]]; then
echo "::error::Script VERSION ($script_version) does not match tag ($tag_version)"
echo "Please update VERSION in ru before tagging"
exit 1
fi
echo "Version check passed: $tag_version"
- name: Verify VERSION file matches tag
run: |
if [[ -f VERSION ]]; then
file_version=$(cat VERSION)
tag_version="${{ steps.version.outputs.version }}"
if [[ "$file_version" != "$tag_version" ]]; then
echo "::error::VERSION file ($file_version) does not match tag ($tag_version)"
exit 1
fi
fi
- name: Compute SHA256 checksums
run: |
echo "Computing checksums..."
sha256sum ru install.sh > checksums.txt
cat checksums.txt
- name: Create individual checksum files
run: |
sha256sum ru | awk '{print $1}' > ru.sha256
sha256sum install.sh | awk '{print $1}' > install.sh.sha256
- name: Generate release notes
run: |
cat > release_notes.md << 'EOF'
## Installation
```bash
curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/repo_updater/main/install.sh | bash
```
## Verify Installation (Optional)
After downloading, verify the checksum:
```bash
# Verify ru script
echo "$(curl -fsSL https://github.com/Dicklesworthstone/repo_updater/releases/download/v${{ steps.version.outputs.version }}/ru.sha256) ru" | sha256sum -c -
```
## Checksums
SHA256 checksums for this release are attached as `checksums.txt`.
EOF
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: ru v${{ steps.version.outputs.version }}
body_path: release_notes.md
files: |
ru
install.sh
checksums.txt
ru.sha256
install.sh.sha256
generate_release_notes: true
append_body: true
fail_on_unmatched_files: true
outputs:
version: ${{ steps.version.outputs.version }}
# ==========================================================================
# Notify Package Managers to Update
# ==========================================================================
notify-homebrew-tap:
name: Notify Homebrew Tap
runs-on: ubuntu-latest
needs: release
# Only run if the secret is configured
if: ${{ vars.HOMEBREW_TAP_ENABLED == 'true' || github.repository == 'Dicklesworthstone/repo_updater' }}
steps:
- name: Check for dispatch token
id: check_token
run: |
if [[ -z "${{ secrets.HOMEBREW_TAP_TOKEN }}" ]]; then
echo "::warning::HOMEBREW_TAP_TOKEN secret not configured - skipping Homebrew notification"
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Trigger formula update
if: steps.check_token.outputs.skip != 'true'
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
repository: Dicklesworthstone/homebrew-tap
event-type: formula-update
client-payload: |
{
"tool": "ru",
"version": "${{ needs.release.outputs.version }}",
"sha": "${{ github.sha }}",
"actor": "${{ github.actor }}"
}
- name: Log dispatch
if: steps.check_token.outputs.skip != 'true'
run: |
echo "Dispatched formula-update event to homebrew-tap"
echo " Tool: ru"
echo " Version: ${{ needs.release.outputs.version }}"
# User's private repo list examples (development only)
je_*.txt
# XDG runtime files (if accidentally placed here)
*.log
logs/
# Editor/IDE
.vscode/
.idea/
*.swp
*.swo
*~
# macOS
.DS_Store
.AppleDouble
.LSOverride
# Linux
.Trash-*
# Temporary files
*.tmp
*.temp
# Test artifacts
test-repos/
/tmp/
a.out
# Debug artifacts
*.debug
# Node modules (if ever used for testing)
node_modules/
# Vim session
Session.vim
# bv (beads viewer) local config and caches
.bv/
# Beads ephemeral files
.beads/last-touched
.beads/.bv.lock
Agent-Friendliness Report: ru (repo_updater)
Bead ID: bd-21i (re-underwriting) Date: 2026-01-25 Agent: Claude Opus 4.5
Executive Summary
Status: EXCELLENT AGENT-FRIENDLINESS MATURITY
ru is highly optimized for AI coding agent repository management:
--jsonflag for structured output--non-interactivefor CI/automation- Comprehensive status and sync commands
- Comprehensive AGENTS.md documentation (22KB)
1. Current State Assessment
1.1 Robot Mode Support
| Feature | Status | Details |
|---|---|---|
--json flag | YES | JSON output to stdout |
--quiet / -q flag | YES | Minimal output (errors only) |
--verbose flag | YES | Detailed output |
--non-interactive | YES | Never prompt (for CI) |
--dry-run | YES | Preview without changes |
1.2 Key Commands
| Command | Purpose |
|---|---|
sync | Clone missing repos, pull updates |
status | Show repository status (default) |
list | Show configured repositories |
doctor | Run system diagnostics |
prune | Find and manage orphan repos |
review | Review GitHub issues/PRs |
add/remove | Manage repo list |
1.3 Output Structure (status)
[
{
"repo": "Dicklesworthstone/example",
"path": "/data/projects/example",
"status": "current",
"branch": "main",
"ahead": 0,
"behind": 0,
"dirty": false,
"mismatch": false
}
]1.4 Sync Features
--clone-only: Only clone missing repos--pull-only: Only pull existing repos--autostash: Stash changes before pull--rebase: Use git pull --rebase--resume: Resume interrupted sync--parallel N: Concurrent sync
2. Documentation Assessment
2.1 AGENTS.md
Status: EXISTS and comprehensive (22KB)
Contains:
- Rule 1: Absolute file deletion protection
- Git safety guidelines
- Conflict handling rules
- Concurrent operation patterns
- Dry-run semantics
2.2 Additional Documentation
- README.md: Usage guide
- Built-in help:
ru --help,ru <cmd> --help ru doctor: Self-diagnostics
3. Scorecard
| Dimension | Score (1-5) | Notes |
|---|---|---|
| Documentation | 5 | Comprehensive AGENTS.md |
| CLI Ergonomics | 5 | Intuitive command structure |
| Robot Mode | 5 | Excellent JSON + dry-run support |
| Error Handling | 5 | Structured status output |
| Consistency | 5 | Unified output format |
| Zero-shot Usability | 5 | Doctor + status commands |
| Overall | 5.0 | Excellent maturity |
4. TOON Integration Status
Status: NOT YET IMPLEMENTED
May benefit from TOON for large repository lists.
5. Recommendations
5.1 High Priority (P1)
None - ru is already exceptionally agent-friendly
5.2 Medium Priority (P2)
1. Add TOON format option 2. Add RU_OUTPUT_FORMAT environment variable
5.3 Low Priority (P3)
1. Add schema export option 2. Document exit codes
6. Agent Usage Patterns
Status Check with JSON
ru status --jsonDry-Run Sync
ru sync --dry-run --jsonNon-Interactive Sync
ru sync --non-interactive --jsonSystem Diagnostics
ru doctor --jsonResume Interrupted Sync
ru sync --resume --json7. Unique Agent-Friendly Features
1. Dry-Run: Preview all operations 2. Resume: Recover from interruptions 3. Non-Interactive: Perfect for CI/automation 4. Status Fields: ahead/behind/dirty/mismatch 5. Parallel Sync: Configurable concurrency
8. Conclusion
ru demonstrates exceptional agent-friendliness with:
- Comprehensive JSON output
- Dry-run and non-interactive modes
- Resume capability for reliability
- Rich status information
Score: 5.0/5 - Exceptional maturity.
--- Generated by Claude Opus 4.5 during agent-friendly re-underwriting
AGENTS.md — repo_updater
Guidelines for AI coding agents working in this Bash codebase.
---
RULE 0 - THE FUNDAMENTAL OVERRIDE PREROGATIVE
If I tell you to do something, even if it goes against what follows below, YOU MUST LISTEN TO ME. I AM IN CHARGE, NOT YOU.
---
RULE NUMBER 1: NO FILE DELETION
YOU ARE NEVER ALLOWED TO DELETE A FILE WITHOUT EXPRESS PERMISSION. Even a new file that you yourself created, such as a test code file. You have a horrible track record of deleting critically important files or otherwise throwing away tons of expensive work. As a result, you have permanently lost any and all rights to determine that a file or folder should be deleted.
YOU MUST ALWAYS ASK AND RECEIVE CLEAR, WRITTEN PERMISSION BEFORE EVER DELETING A FILE OR FOLDER OF ANY KIND.
---
Irreversible Git & Filesystem Actions — DO NOT EVER BREAK GLASS
1. Absolutely forbidden commands: git reset --hard, git clean -fd, rm -rf, or any command that can delete or overwrite code/data must never be run unless the user explicitly provides the exact command and states, in the same message, that they understand and want the irreversible consequences. 2. No guessing: If there is any uncertainty about what a command might delete or overwrite, stop immediately and ask the user for specific approval. "I think it's safe" is never acceptable. 3. Safer alternatives first: When cleanup or rollbacks are needed, request permission to use non-destructive options (git status, git diff, git stash, copying to backups) before ever considering a destructive command. 4. Mandatory explicit plan: Even after explicit user authorization, restate the command verbatim, list exactly what will be affected, and wait for a confirmation that your understanding is correct. Only then may you execute it—if anything remains ambiguous, refuse and escalate. 5. Document the confirmation: When running any approved destructive command, record (in the session notes / final response) the exact user text that authorized it, the command actually run, and the execution time. If that record is absent, the operation did not happen.
---
Git Branch: ONLY Use main, NEVER master
The default branch is `main`. The `master` branch exists only for legacy URL compatibility.
- All work happens on `main` — commits, PRs, feature branches all merge to
main - Never reference `master` in code or docs — if you see
masteranywhere, it's a bug that needs fixing - The `master` branch must stay synchronized with `main` — after pushing to
main, also push tomaster:
git push origin main:masterIf you see `master` referenced anywhere: 1. Update it to main 2. Ensure master is synchronized: git push origin main:master
---
Toolchain: Bash & ShellCheck
This is a pure Bash project. The main script ru and install.sh are shell scripts.
- Shebang:
#!/usr/bin/env bash - Target: Bash 4.0+ compatibility
- Error handling:
set -uo pipefail(do NOT useset -eglobally — handle errors explicitly to ensure processing continues after individual repo failures) - Linter: ShellCheck — address all warnings at severity
warningor higher - No build step: No compilation; scripts are executed directly
Shell Discipline
- No string parsing for git status — use git plumbing commands (e.g.,
git rev-list --left-right --count) - No global `cd` — always use
git -C "$repo_path"instead - Stream separation — stderr for human-readable output, stdout for structured data (JSON, paths)
- Explicit error handling — capture exit codes with
if output=$(cmd 2>&1); then ... else exit_code=$?; fi
Key Dependencies
| Dependency | Purpose |
|---|---|
git | Version control, clone/pull operations |
gh | GitHub CLI (private repos, auth, API calls) |
curl | Installer and self-update downloads |
jq | JSON parsing (optional, for advanced scripting) |
gum | Beautiful terminal UI (optional, ANSI fallback when absent) |
ShellCheck | Shell script linting |
---
Code Editing Discipline
No Script-Based Changes
NEVER run a script that processes/changes code files in this repo. Brittle regex-based transformations create far more problems than they solve.
- Always make code changes manually, even when there are many instances
- For many simple changes: use parallel subagents
- For subtle/complex changes: do them methodically yourself
No File Proliferation
If you want to change something or add a feature, revise existing code files in place.
NEVER create variations like:
ru_v2ru_improvedinstall_enhanced.sh
New files are reserved for genuinely new functionality that makes zero sense to include in any existing file. The bar for creating new files is incredibly high.
---
Backwards Compatibility
We do not care about backwards compatibility—we're in early development with no users. We want to do things the RIGHT way with NO TECH DEBT.
- Never create "compatibility shims"
- Never create wrapper functions for deprecated APIs
- Just fix the code directly
---
Compiler Checks (CRITICAL)
After any substantive code changes, you MUST verify no errors were introduced:
# Check for ShellCheck warnings (main script + installer)
shellcheck -s bash -S warning ru install.sh
# Verify syntax of all shell scripts
bash -n ru
bash -n install.sh
for f in scripts/*.sh; do bash -n "$f"; done
# Run the full test suite
bash scripts/run_all_tests.shIf you see errors, carefully understand and resolve each issue. Read sufficient context to fix them the RIGHT way.
---
Testing
Testing Policy
All tests are shell scripts in scripts/. Tests must cover:
- Happy path
- Edge cases (empty input, missing files, boundary conditions)
- Error conditions
Running Tests
# Run the full test suite
bash scripts/run_all_tests.sh
# Run a specific test file
bash scripts/test_unit_parsing_functions.sh
bash scripts/test_e2e_sync_workflow.sh
bash scripts/test_local_git.sh
# Run unit tests by category
bash scripts/test_unit_argument_parsing.sh
bash scripts/test_unit_config.sh
bash scripts/test_unit_core_utils.sh
bash scripts/test_unit_repo_list.shTest Categories
| Category | Focus Areas |
|---|---|
test_unit_*.sh | Individual function testing: parsing, config, utilities, gum wrappers, state locking, review, worktree, checkpoint, completions |
test_e2e_*.sh | End-to-end workflows: sync, clone, pull, status, init, config, add/remove, prune, doctor, self-update, review, fork operations |
test_local_git.sh | Integration tests with local git repositories |
test_parsing.sh | URL parsing tests |
test_security_guardrails.sh | Security-related test coverage |
test_framework.sh | Test framework infrastructure itself |
test_coverage.sh | Test coverage analysis |
Test Fixtures
Test fixtures live in test/fixtures/:
gh/graphql_batch.json— Mock GitHub GraphQL API responsesplans/*.json— Plan validation test cases (valid, invalid, edge cases)
Development Workspace Hygiene
CRITICAL: Do NOT create git worktrees, clones, or any other directories in /data/projects/ (or the user's projects directory). This directory is managed by ru and should only contain repositories that are configured in ru.
Forbidden Actions:
git worktree add /data/projects/repo_updater_*— creates clutter that confuses users- Cloning repos to
/data/projects/for "testing" or "exploration" - Creating any subdirectories in the projects folder that are not managed by
ru
Correct Approaches: 1. Use `/tmp/` — create temporary directories with mktemp -d 2. Use the existing repo — work in the current checkout, create branches if needed 3. Clean up after yourself — if you must create temporary files/dirs, remove them when done
The E2E tests demonstrate the correct pattern:
TEMP_DIR=$(mktemp -d)
export RU_PROJECTS_DIR="$TEMP_DIR/projects"
# ... run tests ...
rm -rf "$TEMP_DIR" # cleanup---
Third-Party Library Usage
If you aren't 100% sure how to use a third-party library, SEARCH ONLINE to find the latest documentation and current best practices.
---
repo_updater — This Project
This is the project you're working on. repo_updater (ru) is a robust, automation-friendly CLI tool that synchronizes a collection of GitHub repositories to a local projects directory.
What It Does
One-liner curl-bash installation with checksum verification. XDG-compliant configuration. Automatic gh CLI detection. Beautiful gum-powered terminal UI with ANSI fallbacks. Intelligent clone/pull logic using git plumbing (not string parsing). Automation-grade design with meaningful exit codes, non-interactive mode, and JSON output.
Subcommand Architecture
| Command | Purpose | Key Options |
|---|---|---|
sync | Clone/pull repositories | --clone-only, --pull-only, --autostash, --rebase, --dry-run |
status | Show repo status (read-only) | --fetch (default), --no-fetch |
init | Create config directory and files | --example (include example repos) |
add | Add repo to list | --private, --from-cwd |
list | Show configured repos | --public, --private, --paths |
doctor | System diagnostics | (none) |
self-update | Update ru | --check (check only, do not update) |
config | Show/set configuration | --print, --set KEY=VALUE |
robot-docs | Machine-readable CLI docs (JSON) | <topic>: quickstart, commands, examples, exit-codes, formats, schemas, all |
Repo Layout
repo_updater/
├── ru # Main script (~22K LOC)
├── install.sh # Curl-bash installer (~860 LOC)
├── VERSION # Semver version file (e.g., "1.2.1")
├── README.md # Comprehensive documentation
├── AGENTS.md # This file
├── LICENSE # MIT License
├── PLAN_TO_CREATE_UPDATE_REPO_TOOL.md # Detailed implementation plan
├── .gitignore # Ignore runtime artifacts
├── .github/
│ └── workflows/
│ ├── ci.yml # ShellCheck, syntax, behavioral tests
│ └── release.yml # GitHub releases with checksums
├── scripts/
│ ├── run_all_tests.sh # Master test runner
│ ├── test_framework.sh # Test framework infrastructure
│ ├── test_stubs.sh # Test stubs/mocks
│ ├── test_unit_*.sh # Unit tests (~40 files)
│ ├── test_e2e_*.sh # E2E tests (~20 files)
│ ├── test_local_git.sh # Local git integration tests
│ ├── test_parsing.sh # URL parsing tests
│ └── test_coverage.sh # Coverage analysis
├── test/
│ └── fixtures/
│ ├── gh/graphql_batch.json # Mock GitHub API responses
│ └── plans/*.json # Plan validation fixtures
└── examples/
├── public.txt # Example public repos list
├── private.template.txt # Empty template for private repos
└── github-review.yaml # Example review configurationCritical: No je_*.txt files in repo. Those are examples only. User's actual lists live in XDG config (~/.config/ru/repos.d/).
XDG Configuration Layout
~/.config/ru/
├── config # Key-value configuration
└── repos.d/
├── public.txt # User's public repos
└── private.txt # User's private repos (optional)
~/.cache/ru/
└── (runtime cache)
~/.local/state/ru/
├── logs/
│ ├── YYYY-MM-DD/
│ │ ├── run.log # Main run log
│ │ └── repos/
│ │ └── *.log # Per-repo logs
│ └── latest -> YYYY-MM-DD # Symlink to latest run
└── archived/ # Orphan repos moved here by `ru prune`Exit Codes
| Code | Meaning | When |
|---|---|---|
0 | Success | All repos synced or already current |
1 | Partial failure | Some repos failed (network/auth) |
2 | Conflicts exist | Some repos have conflicts needing resolution |
3 | Dependency/system error | gh missing, auth failed, doctor issues |
4 | Invalid arguments | Bad CLI options, missing files |
5 | Interrupted sync | Use --resume or --restart to continue |
Console Output Design
Output stream rules:
- stderr: All human-readable output (progress, errors, summary, help)
- stdout: Only structured output (JSON in
--jsonmode, paths otherwise)
Visual design:
- Use gum when available for beautiful terminal UI
- Fall back to ANSI color codes when gum is unavailable
- Non-interactive mode (
--non-interactive) suppresses prompts for CI/automation
Generated Files — NEVER Edit Manually
Current state: There are no checked-in generated source files in this repo.
If/when we add generated artifacts:
- Rule: Never hand-edit generated outputs.
- Convention: Put generated outputs in a clearly labeled directory and document the generator command adjacent to it.
---
MCP Agent Mail — Multi-Agent Coordination
A mail-like layer that lets coding agents coordinate asynchronously via MCP tools and resources. Provides identities, inbox/outbox, searchable threads, and advisory file reservations with human-auditable artifacts in Git.
Why It's Useful
- Prevents conflicts: Explicit file reservations (leases) for files/globs
- Token-efficient: Messages stored in per-project archive, not in context
- Quick reads:
resource://inbox/...,resource://thread/...
Same Repository Workflow
1. Register identity:
ensure_project(project_key=<abs-path>)
register_agent(project_key, program, model)2. Reserve files before editing:
file_reservation_paths(project_key, agent_name, ["ru", "install.sh"], ttl_seconds=3600, exclusive=true)3. Communicate with threads:
send_message(..., thread_id="FEAT-123")
fetch_inbox(project_key, agent_name)
acknowledge_message(project_key, agent_name, message_id)4. Quick reads:
resource://inbox/{Agent}?project=<abs-path>&limit=20
resource://thread/{id}?project=<abs-path>&include_bodies=trueMacros vs Granular Tools
- Prefer macros for speed:
macro_start_session,macro_prepare_thread,macro_file_reservation_cycle,macro_contact_handshake - Use granular tools for control:
register_agent,file_reservation_paths,send_message,fetch_inbox,acknowledge_message
Common Pitfalls
"from_agent not registered": Alwaysregister_agentin the correctproject_keyfirst"FILE_RESERVATION_CONFLICT": Adjust patterns, wait for expiry, or use non-exclusive reservation- Auth errors: If JWT+JWKS enabled, include bearer token with matching
kid
---
Beads (br) — Dependency-Aware Issue Tracking
Beads provides a lightweight, dependency-aware issue database and CLI (br - beads_rust) for selecting "ready work," setting priorities, and tracking status. It complements MCP Agent Mail's messaging and file reservations.
Important: br is non-invasive—it NEVER runs git commands automatically. You must manually commit changes after br sync --flush-only.
SQLite/WAL Caution: br uses SQLite with WAL mode. Always run br sync --flush-only before git operations to ensure .beads/ files are consistent.
Conventions
- Single source of truth: Beads for task status/priority/dependencies; Agent Mail for conversation and audit
- Shared identifiers: Use Beads issue ID (e.g.,
br-123) as Mailthread_idand prefix subjects with[br-123] - Reservations: When starting a task, call
file_reservation_paths()with the issue ID inreason
Typical Agent Flow
1. Pick ready work (Beads):
br ready --json # Choose highest priority, no blockers2. Reserve edit surface (Mail):
file_reservation_paths(project_key, agent_name, ["ru", "install.sh"], ttl_seconds=3600, exclusive=true, reason="br-123")3. Announce start (Mail):
send_message(..., thread_id="br-123", subject="[br-123] Start: <title>", ack_required=true)4. Work and update: Reply in-thread with progress
5. Complete and release:
br close 123 --reason "Completed"
br sync --flush-only # Export to JSONL (no git operations) release_file_reservations(project_key, agent_name, paths=["ru", "install.sh"])Final Mail reply: [br-123] Completed with summary
Mapping Cheat Sheet
| Concept | Value |
|---|---|
Mail thread_id | br-### |
| Mail subject | [br-###] ... |
File reservation reason | br-### |
| Commit messages | Include br-### for traceability |
---
bv — Graph-Aware Triage Engine
bv is a graph-aware triage engine for Beads projects (.beads/beads.jsonl). It computes PageRank, betweenness, critical path, cycles, HITS, eigenvector, and k-core metrics deterministically.
Scope boundary: bv handles what to work on (triage, priority, planning). For agent-to-agent coordination (messaging, work claiming, file reservations), use MCP Agent Mail.
*CRITICAL: Use ONLY `--robot- flags. Bare bv` launches an interactive TUI that blocks your session.**
The Workflow: Start With Triage
`bv --robot-triage` is your single entry point. It returns:
quick_ref: at-a-glance counts + top 3 picksrecommendations: ranked actionable items with scores, reasons, unblock infoquick_wins: low-effort high-impact itemsblockers_to_clear: items that unblock the most downstream workproject_health: status/type/priority distributions, graph metricscommands: copy-paste shell commands for next steps
bv --robot-triage # THE MEGA-COMMAND: start here
bv --robot-next # Minimal: just the single top pick + claim commandCommand Reference
Planning:
| Command | Returns |
|---|---|
--robot-plan | Parallel execution tracks with unblocks lists |
--robot-priority | Priority misalignment detection with confidence |
Graph Analysis:
| Command | Returns |
|---|---|
--robot-insights | Full metrics: PageRank, betweenness, HITS, eigenvector, critical path, cycles, k-core, articulation points, slack |
--robot-label-health | Per-label health: health_level, velocity_score, staleness, blocked_count |
--robot-label-flow | Cross-label dependency: flow_matrix, dependencies, bottleneck_labels |
--robot-label-attention [--attention-limit=N] | Attention-ranked labels |
History & Change Tracking:
| Command | Returns |
|---|---|
--robot-history | Bead-to-commit correlations |
--robot-diff --diff-since <ref> | Changes since ref: new/closed/modified issues, cycles |
Other:
| Command | Returns |
|---|---|
--robot-burndown <sprint> | Sprint burndown, scope changes, at-risk items |
| `--robot-forecast <id\ | all>` |
--robot-alerts | Stale issues, blocking cascades, priority mismatches |
--robot-suggest | Hygiene: duplicates, missing deps, label suggestions |
| `--robot-graph [--graph-format=json\ | dot\ |
--export-graph <file.html> | Interactive HTML visualization |
Scoping & Filtering
bv --robot-plan --label backend # Scope to label's subgraph
bv --robot-insights --as-of HEAD~30 # Historical point-in-time
bv --recipe actionable --robot-plan # Pre-filter: ready to work
bv --recipe high-impact --robot-triage # Pre-filter: top PageRank
bv --robot-triage --robot-triage-by-track # Group by parallel work streams
bv --robot-triage --robot-triage-by-label # Group by domainUnderstanding Robot Output
All robot JSON includes:
data_hash— Fingerprint of source beads.jsonlstatus— Per-metric state:computed|approx|timeout|skipped+ elapsed msas_of/as_of_commit— Present when using--as-of
Two-phase analysis:
- Phase 1 (instant): degree, topo sort, density
- Phase 2 (async, 500ms timeout): PageRank, betweenness, HITS, eigenvector, cycles
jq Quick Reference
bv --robot-triage | jq '.quick_ref' # At-a-glance summary
bv --robot-triage | jq '.recommendations[0]' # Top recommendation
bv --robot-plan | jq '.plan.summary.highest_impact' # Best unblock target
bv --robot-insights | jq '.status' # Check metric readiness
bv --robot-insights | jq '.Cycles' # Circular deps (must fix!)---
UBS — Ultimate Bug Scanner
Golden Rule: ubs <changed-files> before every commit. Exit 0 = safe. Exit >0 = fix & re-run.
Commands
ubs ru install.sh # Specific files (< 1s) — USE THIS
ubs $(git diff --name-only --cached) # Staged files — before commit
ubs --only=bash scripts/ # Language filter
ubs --ci --fail-on-warning . # CI mode — before PR
ubs . # Whole projectOutput Format
Warning Category (N errors)
file.sh:42:5 – Issue description
Suggested fix
Exit code: 1Parse: file:line:col -> location | Suggested fix -> how to fix | Exit 0/1 -> pass/fail
Fix Workflow
1. Read finding -> category + fix suggestion 2. Navigate file:line:col -> view context 3. Verify real issue (not false positive) 4. Fix root cause (not symptom) 5. Re-run ubs <file> -> exit 0 6. Commit
Bug Severity
- Critical (always fix): Command injection, unquoted variables, path traversal
- Important (production): Unhandled exit codes, missing error messages, resource leaks
- Contextual (judgment): TODO/FIXME, echo debugging
---
RCH — Remote Compilation Helper
RCH offloads cargo build, cargo test, cargo clippy, and other compilation commands to a fleet of 8 remote Contabo VPS workers instead of building locally. This prevents compilation storms from overwhelming csd when many agents run simultaneously.
RCH is installed at `~/.local/bin/rch` and is hooked into Claude Code's PreToolUse automatically. Most of the time you don't need to do anything if you are Claude Code — builds are intercepted and offloaded transparently.
To manually offload a build:
rch exec -- cargo build --release
rch exec -- cargo test
rch exec -- cargo clippyQuick commands:
rch doctor # Health check
rch workers probe --all # Test connectivity to all 8 workers
rch status # Overview of current state
rch queue # See active/waiting buildsIf rch or its workers are unavailable, it fails open — builds run locally as normal.
Note for Codex/GPT-5.2: Codex does not have the automatic PreToolUse hook, but you can (and should) still manually offload compute-intensive compilation commands using rch exec -- <command>. This avoids local resource contention when multiple agents are building simultaneously.
---
ast-grep vs ripgrep
Use `ast-grep` when structure matters. It parses code and matches AST nodes, ignoring comments/strings, and can safely rewrite code.
- Refactors/codemods: rename APIs, change import forms
- Policy checks: enforce patterns across a repo
- Editor/automation: LSP mode,
--jsonoutput
Use `ripgrep` when text is enough. Fastest way to grep literals/regex.
- Recon: find strings, TODOs, log lines, config values
- Pre-filter: narrow candidate files before ast-grep
Rule of Thumb
- Need correctness or applying changes ->
ast-grep - Need raw speed or hunting text ->
rg - Often combine:
rgto shortlist files, thenast-grepto match/modify
Shell Examples
# Find structured code (ignores comments)
ast-grep run -l Bash -p 'if $COND; then $$$BODY fi'
# Quick textual hunt
rg -n 'set -e' -t sh
# Combine speed + precision
rg -l -t sh 'parse_repo_url' | xargs ast-grep run -l Bash --json---
Morph Warp Grep — AI-Powered Code Search
Use `mcp__morph-mcp__warp_grep` for exploratory "how does X work?" questions. An AI agent expands your query, greps the codebase, reads relevant files, and returns precise line ranges with full context.
Use `ripgrep` for targeted searches. When you know exactly what you're looking for.
Use `ast-grep` for structural patterns. When you need AST precision for matching/rewriting.
When to Use What
| Scenario | Tool | Why |
|---|---|---|
| "How does gh auth check work?" | warp_grep | Exploratory; don't know where to start |
| "How does URL parsing handle git@ SSH URLs?" | warp_grep | Need to understand architecture |
"Find all uses of parse_repo_url" | ripgrep | Targeted literal search |
"Find files with set -e" | ripgrep | Simple pattern |
"Replace all var with let" | ast-grep | Structural refactor |
warp_grep Usage
mcp__morph-mcp__warp_grep(
repoPath: "/dp/repo_updater",
query: "How does URL parsing handle git@ SSH URLs?"
)Returns structured results with file paths, line ranges, and extracted code snippets.
Anti-Patterns
- Don't use
warp_grepto find a specific function name -> useripgrep - Don't use
ripgrepto understand "how does X work" -> wastes time with manual reads - Don't use
ripgrepfor codemods -> risks collateral edits
---
cass — Cross-Agent Search
cass indexes prior agent conversations (Claude Code, Codex, Cursor, Gemini, ChatGPT, etc.) so we can reuse solved problems.
Rules:
- Never run bare
cass(TUI). Always use--robotor--json.
Examples:
cass health
cass search "bash error handling" --robot --limit 5
cass view /path/to/session.jsonl -n 42 --json
cass expand /path/to/session.jsonl -n 42 -C 3 --json
cass capabilities --json
cass robot-docs guideTips:
- Use
--fields minimalfor lean output. - Filter by agent with
--agent. - Use
--days Nto limit to recent history.
stdout is data-only, stderr is diagnostics; exit code 0 means success.
Treat cass as a way to avoid re-solving problems other agents already handled.
---
Memory System: cass-memory
The Cass Memory System (cm) is a tool for giving agents an effective memory based on the ability to quickly search across previous coding agent sessions and then reflect on what they find and learn in new sessions to draw out useful lessons and takeaways.
Quick Start
# 1. Check status and see recommendations
cm onboard status
# 2. Get sessions to analyze (filtered by gaps in your playbook)
cm onboard sample --fill-gaps
# 3. Read a session with rich context
cm onboard read /path/to/session.jsonl --template
# 4. Add extracted rules (one at a time or batch)
cm playbook add "Your rule content" --category "debugging"
# 5. Mark session as processed
cm onboard mark-done /path/to/session.jsonlBefore starting complex tasks, retrieve relevant context:
cm context "<task description>" --jsonThis returns:
- relevantBullets: Rules that may help with your task
- antiPatterns: Pitfalls to avoid
- historySnippets: Past sessions that solved similar problems
- suggestedCassQueries: Searches for deeper investigation
Protocol
1. START: Run cm context "<task>" --json before non-trivial work 2. WORK: Reference rule IDs when following them (e.g., "Following b-8f3a2c...") 3. FEEDBACK: Leave inline comments when rules help/hurt 4. END: Just finish your work. Learning happens automatically.
<!-- bv-agent-instructions-v1 -->
---
Beads Workflow Integration
This project uses beads_rust (br) for issue tracking. Issues are stored in .beads/ and tracked in git.
Important: br is non-invasive—it NEVER executes git commands. After br sync --flush-only, you must manually run git add .beads/ && git commit.
Essential Commands
# View issues (launches TUI - avoid in automated sessions)
bv
# CLI commands for agents (use these instead)
br ready # Show issues ready to work (no blockers)
br list --status=open # All open issues
br show <id> # Full issue details with dependencies
br create --title="..." --type=task --priority=2
br update <id> --status=in_progress
br close <id> --reason "Completed"
br close <id1> <id2> # Close multiple issues at once
br sync --flush-only # Export to JSONL (NO git operations)Workflow Pattern
1. Start: Run br ready to find actionable work 2. Claim: Use br update <id> --status=in_progress 3. Work: Implement the task 4. Complete: Use br close <id> 5. Sync: Run br sync --flush-only then manually commit
Key Concepts
- Dependencies: Issues can block other issues.
br readyshows only unblocked work. - Priority: P0=critical, P1=high, P2=medium, P3=low, P4=backlog (use numbers, not words)
- Types: task, bug, feature, epic, chore
- Blocking:
br dep add <issue> <depends-on>to add dependencies
Session Protocol
Before ending any session, run this checklist:
git status # Check what changed
git add <files> # Stage code changes
br sync --flush-only # Export beads to JSONL
git add .beads/ # Stage beads changes
git commit -m "..." # Commit everything together
git push # Push to remoteBest Practices
- Check
br readyat session start to find available work - Update status as you work (in_progress -> closed)
- Create new issues with
br createwhen you discover tasks - Use descriptive titles and set appropriate priority/type
- Always
br sync --flush-only && git add .beads/before ending session
<!-- end-bv-agent-instructions -->
Landing the Plane (Session Completion)
When ending a work session, you MUST complete ALL steps below.
MANDATORY WORKFLOW:
1. File issues for remaining work - Create issues for anything that needs follow-up 2. Run quality gates (if code changed) - Tests, linters, builds 3. Update issue status - Close finished work, update in-progress items 4. Sync beads - br sync --flush-only to export to JSONL 5. Hand off - Provide context for next session
---
Note for Codex/GPT-5.2:
You constantly bother me and stop working with concerned questions that look similar to this:
Unexpected changes (need guidance)
- Working tree still shows edits I did not make in ru, install.sh, scripts/test_unit_parsing_functions.sh. Please advise whether to keep/commit/revert these before any further work. I did not touch them.
Next steps (pick one)
1. Decide how to handle the unrelated modified files above so we can resume cleanly.
2. Triage open beads issues.
3. If you want a full suite run later, fix ShellCheck blockers and re-run.NEVER EVER DO THAT AGAIN. The answer is literally ALWAYS the same: those are changes created by the potentially dozen of other agents working on the project at the same time. This is not only a common occurrence, it happens multiple times PER MINUTE. The way to deal with it is simple: you NEVER, under ANY CIRCUMSTANCE, stash, revert, overwrite, or otherwise disturb in ANY way the work of other agents. Just treat those changes identically to changes that you yourself made. Just fool yourself into thinking YOU made the changes and simply don't recall it for some reason.
---
Note on Built-in TODO Functionality
Also, if I ask you to explicitly use your built-in TODO functionality, don't complain about this and say you need to use beads. You can use built-in TODOs if I tell you specifically to do so. Always comply with such orders.
Changelog
All notable changes to ru (Repo Updater) are documented here.
Format: Keep a Changelog. Versioning: SemVer.
Links point to individual commits on GitHub. Version headers link to comparison views between tags.
---
Unreleased
Ongoing development since v1.2.1 (2026-01-09). Includes new commands, output formats, fork management groundwork, and significant test hardening.
New Commands
- `commit-sweep` -- Groups dirty worktrees into logical commits, useful for multi-agent workflows where many repos accumulate changes simultaneously (d3dab9e)
- `robot-docs` -- Machine-readable CLI documentation emitted as JSON; covers topics: commands, quickstart, examples, exit-codes, formats, schemas (0ebe82d)
- `--schema` shortcut -- Equivalent to
ru robot-docs schemasfor quick schema access (10f504e) - `ai-sync` -- AI-assisted sync that analyzes repo state and suggests next steps (5db62f2)
- `dep-update` -- Dependency update scanning with package manager auto-detection (npm, cargo, go, pip, etc.) (5db62f2)
Output & Structured Data
- TOON output format --
--format json|toonflag for structured output in both JSON and TOON encodings (22cd33f) - Normalized JSON output envelope across sync/status/list commands for consistent parsing (40b40b1)
- README: replaced
--format jsonreferences with--json(2595153)
Fork Management (Groundwork)
- Argument parsing for fork management commands:
fork-status,fork-sync,fork-clean(a7aa3d5) - Extended fork command argument parser with additional option handling (89f89f2)
- Fork management E2E test scaffolding (1e0fa15)
Agent & Automation Integration
- Claude Code SKILL.md for automatic capability discovery (c1e1601)
ru-reviewskill: Twitter check requirement, NO MERGING policy enforcement (6d88bcd, 86c76e8)- AGENT_FRIENDLINESS_REPORT.md for discoverability assessment (0cb7d16)
- Agent quickstart documentation in README (793492a)
- ACFS notification workflow for installer changes (e269146)
- ACFS checksum dispatch workflow (676c9f5)
Testing
- 55 unit tests for previously untested parsing/resolution functions (ce5ac34)
- Unit tests for review policy functions (201d1c8)
- Unit tests for dirty repo detection, test runner detection, package manager detection (c0e31e9, a3b2ce8, da9c3eb)
- TOON E2E test scripts (fe93794, b67e6f5)
- Real-world JSON fixture outputs for TOON testing (a3d1048)
- Lifecycle unit tests, formula/manifest script tests (3e77a07, 25d24f1)
- Migrated all E2E tests to unified
test_e2e_framework.sh(b90c2b3, fc4f0dc, a258cf9) - Quality gate debug script and mock inspection helpers (c9c698e)
Project & Licensing
- License updated to MIT with OpenAI/Anthropic Rider (6f2db83)
- CONTRIBUTING.md and PR template (9eaae97)
- GitHub social preview image (8ac879f)
- Homebrew installation option documented (bd1d4e5)
- Improved GitHub Actions workflows with security and performance best practices (cd4ffa6)
Bug Fixes
- Three bugs breaking
ru reviewdiscovery summary (21e2c21) - JSON structure in dep-update helpers (1c66a95)
- Dep-update bugs found in code review (fa8a243)
- Agent-sweep specific options added to global arg parser (871b0c3)
- Merge conflict in review driver loading (f0ff0ad)
- Wait for full ntm cycle to prevent premature state reads (15480c5)
- macOS Bash 5 installation in CI -- ncurses dependency, PATH handling, linking (cf7f027, c8c07fa, d0a3f9c, e1445fa)
- EXIT trap collision and redundant cleanup in tests (5aafc5c)
- HOME restored before deleting temp directory in tests (6b82479)
- Quality-gate tests guarded with fresh function source to prevent mock leaking (6313be9, b990404)
- Fork management E2E test assertions and edge cases (b90ad10)
- Recovered files deleted by bd daemon sync (2fcdca5)
---
v1.2.1 -- 2026-01-09
Stability release focused on review orchestration reliability and security hardening. Published as GitHub Release (Latest). All 83 test files passing.
Review Orchestration
- Session queue management for coordinating multiple review sessions (14d2f1e)
- Unified session log discovery and multi-day rate limit scanning (ffa3c84)
start_next_queued_sessionwith work items support (832da3b)- Session monitor implementation for tracking active review sessions (e33a954)
- Output variable support for
apply_state_hysteresis(5dfe0d5) - Review prompt updated to full verbatim policy (94cc1b7)
- Proper state file for session-repo mapping (5cba804)
Security
- Reject newline-separated commands in validation to prevent injection (032c4ee)
- Pre-escape newlines for valid JSON output (5d33c7b)
Orchestration Bug Fixes
self-updateEXIT trap: expandtemp_dirimmediately -- was empty due to single quotes around the local variable (9640be4)- Mark repo as error when driver load fails instead of leaving inconsistent state (a5f062b)
- Properly pass output to
detect_wait_reason(argument order fix) (18584ec) - Skip missing worktrees and add velocity division guard (7aee933)
- Count questions only once per session (fixed double-counting) (95dcc22)
- Session state tracking in orchestration loop (bd7c832)
- Governor: pass active session count to
can_start_new_session(ad0d8e7) start_next_queued_sessionsignature fix in monitor (1f11652)- Worktree branch pin handling improvements (7109a6d)
- Portable date comparison in
is_recently_reviewed(3697b03) - macOS
timeoutcommand compatibility (39beb8d) - Replace heredoc with printf for test compatibility (2b700d4)
Testing
- Comprehensive test suites for review orchestration -- unit and E2E (f036abd, 7e0e953)
- Completion phase tests (764e9e0)
- Apply phase E2E tests (31298c9)
- Question TUI tests (591f162)
- Session monitor tests (7b7c33e)
- Session driver E2E tests (c472906)
- Checkpoint/resume unit and E2E tests (58547db)
- Integration tests and session log improvements (90ae04a)
---
v1.2.0 -- 2026-01-08
Major release introducing Agent Sweep for automated multi-repository AI code review, the git harness for deterministic offline testing, and comprehensive Bash 4.0 compatibility fixes. ~17,700 lines of pure Bash across ~198 commits. Published as GitHub Release (Draft).
Agent Sweep -- AI-Powered Multi-Repository Review
The headline feature: orchestrate AI-assisted code review across many repositories simultaneously.
- `agent-sweep` command -- parallel AI code review with work-stealing queue (6164c57)
- NTM driver and utility functions for tmux session management (df1b0fe)
- Per-repository configuration loading via
.ru-review.yml(8d8dbc5) - Parallel preflight checks and secret scanning (8ebd776)
- Plan extraction from agent pane output (96111c9)
- Phase prompts with structured output markers (fe0c0bb)
- Global rate limit backoff coordination across parallel workers (bbcf212)
- Release workflow detection and execution (0a08f1c)
- Release plan validation and execution (807e72a)
- Commit plan validation and execution with quality gates (e31a6ea)
- File size/binary validation to prevent accidental large commits (cc10475)
- Artifact capture functions (21ce3d2)
- User-friendly error messages (70085c3)
- Verbose and debug logging modes (cf1873b)
- Real-time progress display during sweep (4d8f5bb)
- Enhanced summary with full spec display (dacfba6)
- State recovery with
--resumefor interrupted sweeps (590a7c3) - ntm integration in installer for agent-sweep support (c42973c)
Quality Gates
Validation layer for agent-generated commit plans:
- File size limits, binary file detection, file denylist, test requirements (e31a6ea)
- Nested directory pattern matching in denylist (2a2f146)
- Secret scan: skip detect-secrets gracefully when jq is missing (b83617f)
Testing Infrastructure
- Git harness library -- create temporary git repos with precisely controlled states (ahead, behind, diverged, dirty, shallow, detached) for offline deterministic testing (f3ed8dc)
- Comprehensive testing guide (TESTING.md) (4ed5826)
- Parallel mode tests (944e65a)
- E2E agent-sweep tests (91249ae)
- State management tests (e0de8a1)
- NTM driver unit tests (4c0d005)
- Security guardrail tests (4db8f7e)
- Plan validation tests (7433e06)
- Unit tests for parse_/extract_ functions (c7d51dd)
- Consistent
get_exit_code()usage across all test files (0425685) - Consistent assertion API in git harness tests (2e36cbb)
- 70+ test files total (36 unit, 20 E2E, plus integration), ~700+ assertions
Bash Compatibility
- Bash 4.0-4.3 safe empty array pattern --
${arr[@]+...}prevents unbound variable errors (8e25313) - Prevented glob expansion in word-split iterations (f1fec49)
- Git harness: Bash 4.0 compat and git plumbing for shallow check (d6a340c)
- Boolean exit codes in test scripts (674c397)
- Empty array safety in
save_agent_sweep_state(f2d426e) - Portable
drop_last_linesfor macOS compatibility (5872086)
Sync & Configuration Fixes
no_upstreamstatus handling andwrite_json_atomicerror propagation (f6e91f1, 613a69e)- Regex safety and lock timeout warnings in sync (0b26864)
- Default projects directory aligned with README (15cb25c)
repo_spec_to_pathrespects resolvedPROJECTS_DIRconfig (c7cc90c)resolve_repo_specrespectsRU_CONFIG_DIR(ed21ed8)- Installer: correct regex escaping in checksum pattern (41730c1)
Other Fixes
- Circular nameref and test race condition in parallel mode (3df3c13)
- Numeric
-1for unknown AHEAD/BEHIND values (ddd4ed1) json_get_fieldsed fallback for arrays and booleans (5f26878)- Agent-sweep: repo path validation and resume with-release flag (76480ec)
- Lock directories cleaned up in parallel sync and global cleanup (4f3c625)
- Multiple UX issues found during real-world testing (3ad9bf3)
- Empty array in
discover_tests(8b7878e)
Documentation
- Architecture and testing sections expanded in README (537b957, f68b22a)
- Documented previously undocumented features (fc31bab)
- AGENTS.md: workspace hygiene rules for worktrees (1c6edfa)
- Agent-sweep command documentation in README (a4572e4)
- Testing tiers and logging documentation (f29847d)
---
v1.1.0 -- 2026-01-05
Comprehensive testing and documentation release. Introduces 58 test files, portable directory-based locking, Bash 4.0 compatibility via nameref removal, and extensive README expansion. ~120 commits. GitHub Release.
Testing Infrastructure
- E2E test framework with comprehensive logging and test isolation (792cbcc)
- Test coverage tracking and reporting system (a66d867)
- Test log viewer/filter tool for debugging (327d2f7)
- JSON logging for test framework (daee60b)
- Parallel test execution with job limiting (9edf815)
- Enhanced test isolation functions (e6159d2)
- Standardized assert function signatures (message-first pattern) (851ad88)
- Auto-load directory lock helpers in test framework (fe679cc)
E2E Tests Added
- Review workflows (52a799d)
- Sync workflows (be77c77)
- Clone drivers (a5ea194)
- Worktree management (27f28c1)
- Configuration and environment (d39216e)
- Error handling and recovery (3aff887)
Unit Tests Added
- Driver interface layer (90eb5da)
- Local session driver (627c877)
- Rate limiting (6398ba2)
- Metrics and analytics (7352ae6)
- Quality gates (6e86fba)
- GitHub Actions execution (437da26)
- Worktree operations (887e2de)
- Review state management (6674688)
- Locking (2d8cfec)
Compatibility & Portability
- Bash 4.0-4.2 compatibility -- removed all nameref usage (1ec7fd2, 95101b1)
- Bash 4.0-4.2 compatibility for parallel execution (2226a28)
- Flock auto-install -- prompt/auto-install flock when required (b515377)
Installer Hardening
- Self-refresh for piped stdin (f0c6a93)
- Removed flock dependency, avoid GitHub API for version detection (1d7521b)
- Self-refresh + lock cleanup (c4ce425)
- Robust latest release detection (6cac5c2)
- Harden installer/self-update + flock diagnostics (88317de)
- Stream separation + robustness improvements (96be9a1)
- Printf for safer output + redirect-based version detection (1ec7e4a)
Bug Fixes
- Variable shadowing in
resolve_repo_spec,parse_stream_json_event,get_worktree_path(f4508ff, 8db0025, 8864169) - Worktrees: lock mapping + normalize repo IDs (c875870)
- Prune: delete confirmation prompt no longer hangs (4cdf885)
- Review worktree cleanup path safety hardened (8047efd)
- Tests: directory-based locking and return code fixes (959112f)
Documentation
---
v1.0.1 -- 2026-01-05
First official release. Pure Bash CLI for synchronizing GitHub repositories with automation-grade exit codes, JSON output, and a gum-powered terminal UI. ~295 commits from initial commit to first tag over two days of intensive development. GitHub Release.
Repository Synchronization
- `sync` -- Clone missing repos and pull updates with conflict detection; supports
--autostash,--dry-run(ec2cef5) - Parallel sync with worker pool (
--parallel N,-jN) for concurrent processing (72752d2) - Resume support for interrupted syncs (
--resume) (b14cdac) - Branch pinning in ad-hoc sync (29e1ce7)
- Network timeout handling (20441c1)
Repository Management
- `status` -- Show repository status (read-only) with JSON output (8dc6e0e)
- `init` -- Initialize configuration directory with
--exampleflag (69bce88) - `add` / `remove` -- Manage repository list with
--privateand--from-cwdoptions (65ae2b4, 98fa533) - `list` -- Show configured repositories with
--pathsoutput (41ff89e) - `import` -- Bulk repository import from file with auto visibility detection and deduplication (24db5b9, c1998ac)
- `prune` -- Find and manage orphan repositories (81106eb)
- `config` -- Show/set configuration (3b7fd5b)
Diagnostics & Maintenance
- `doctor` -- System diagnostics with review-specific health checks (926919f, 344ba67)
- `self-update` -- Update ru to latest version with checksum verification (ddaf9df)
- Stylish quick menu when
ruinvoked with no arguments (a629dc2)
AI-Assisted Review System
- `review` -- AI-assisted review of issues and PRs with priority scoring (def74c7)
- GraphQL batched repository discovery for 50x API efficiency (2760fe8)
- Wait reason detection with three categories (b2c8ed2)
- ntm driver using robot mode API for tmux session management (8540eba)
- Unified driver interface and local driver (a5efcdb)
- Git worktree preparation for isolated reviews (1166009)
- Command validation and blocking for agent sessions (3b939ac)
- Discovery summary display with priority breakdown (371b422)
- Quality gates framework (bf7f3cb)
- Per-repo review policy configuration (0e0e1ec)
- Non-interactive mode for CI/automation (6696e56)
- GitHub Actions execution from review plan (8f9c68d)
- Review
--statusfor lock/checkpoint inspection (cb5e9dd) - Rate-limit governor for adaptive concurrency (3a3b289)
- Exponential backoff retry helper (17b6945)
Output & Automation
- Meaningful exit codes: 0=ok, 1=partial, 2=conflicts, 3=system, 4=bad args, 5=interrupted (c1cd4f5)
- JSON output (
--json) for structured scripting integration (39707be) - NDJSON logging with path field for conflict help (ea11057)
- Gum-powered terminal UI with ANSI fallbacks (8a39add)
- Reporting and summary functions (39707be)
Infrastructure
- Installation script with SHA256 checksum verification (4197166)
- Centralized repo spec parsing with
resolve_repo_spec(191fc5a) - SSH URL parsing in
parse_repo_spec(41ff89e) - Security: path traversal protection and JSON escaping (8273933)
- TAP output format for test framework (afa21c0)
- Master test runner
run_all_tests.sh(6c67388) - CI: matrix testing on Ubuntu and macOS (6bd01c9)
- CI and release workflows (fda5440)
Pre-Release Testing
- E2E tests: init, sync clone/pull, status, config, doctor, repo spec parsing, edge cases, self-update, installation (4c95bc9...ffef04c)
- Unit tests: core utilities, path sanitization, sync state, dependency checks, argument parsing, repo list management, config, timeout handling, gum wrappers (668a82b...173fa28)
- Review E2E and unit tests with fixtures (173fa28)
- Priority scoring edge case tests (14ccbb6)
- Security: command validation bypass repro coverage (0e8be46)
Bug Fixes
- Diverged status check order in
process_single_repo(00108f8) - Nameref shadowing in
resolve_repo_spec(539ee70) - Exit codes and result tracking in sync (b62cc6d)
- Color detection: check stderr instead of stdout (11d3f57)
- Prune:
log_warnand depth calculation (044b823) - Import: non-GitHub hosts, dead code cleanup (3df929e)
- Missing
write_resultcalls in parallel worker (8e0724f) - Undefined
NCvariable (should beRESET) (d4d1fe7) - Self-update error handling for repos without releases (ddaf9df)
- Installer: handle 404 when no releases exist, cache busting (047d270, b4da2c6)
- Installer: portable mktemp cleanup (40f28ca)
- Rate-limit governor bugs and defensive integer validation (99839bf, 778b93f)
- Dashboard robustness issues (899214d)
get_config_valuequote stripping (7a4ab02)- Review: allow dry-run without driver, allow
--statusinparse_args(7526e7e, f993212) - macOS compatibility + deep code review bug fixes (99a1bc9, f2da8d7)
- ShellCheck warnings across codebase (bb35706, 240eda0)
---
Project Inception -- 2026-01-03
Initial commit (12ba14c): project specification and documentation. Core script skeleton (1849c70) and core feature implementation (ec2cef5) began on the same day; the project reached its first release (v1.0.1) two days later.
Contributing to ru
Bug reports and feature requests via Issues are welcome.
Pull requests will not be merged. I review submissions via gh and independently decide whether and how to address them. If your idea is adopted, it will be reimplemented from scratch. This isn't personal -- it's about keeping maintenance sustainable for a solo project.
Feel free to submit PRs to illustrate a proposed fix, but please understand they serve as reference material, not merge candidates.
# ntm workflow template for ru review (plan mode)
# Copy to ~/.config/ntm/workflows/github-review.yaml
schema_version: "2.0"
name: github-review
description: |
Automated GitHub issue and PR review workflow (plan mode).
Agent produces local patches and review-plan.json artifact.
NO direct GitHub mutations.
inputs:
worktree_path:
description: Path to isolated worktree
required: true
repo_name:
description: GitHub repo identifier (owner/repo)
required: true
repo_digest_path:
description: Optional cached digest path
required: false
work_items:
description: JSON array of items to review
required: true
settings:
timeout: "45m"
on_error: "fail"
notify_on_error: true
defaults:
working_dir: ${inputs.worktree_path}
agent: claude
steps:
- id: verify_prerequisites
type: shell
command: |
if ! command -v gh >/dev/null 2>&1; then
echo "gh is required" >&2
exit 1
fi
if ! gh auth status >/dev/null 2>&1; then
echo "gh auth required" >&2
exit 1
fi
if [[ -z "${inputs.worktree_path}" || ! -d "${inputs.worktree_path}" ]]; then
echo "worktree_path missing or invalid" >&2
exit 1
fi
if ! git -C "${inputs.worktree_path}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "worktree_path is not a git repository" >&2
exit 1
fi
mkdir -p "${inputs.worktree_path}/.ru"
if command -v jq >/dev/null 2>&1; then
if ! echo "${inputs.work_items}" | jq -e 'type == "array"' >/dev/null 2>&1; then
echo "work_items must be a JSON array" >&2
exit 1
fi
fi
on_failure: abort
- id: understand_codebase
agent: claude
depends_on: [verify_prerequisites]
prompt: |
You are working in ${inputs.worktree_path} for ${inputs.repo_name}.
First read ALL of AGENTS.md and README.md for this repository.
If repo_digest_path is provided and readable, load it.
Otherwise, create or update ${inputs.worktree_path}/.ru/repo-digest.md
with a concise summary (purpose, architecture, key modules, recent changes).
Keep the digest updated for future runs.
wait: completion
timeout: 10m
health_check:
interval: 30s
max_stalls: 3
outputs:
digest_path: ${inputs.worktree_path}/.ru/repo-digest.md
- id: review_issues_prs
agent: claude
depends_on: [understand_codebase]
prompt: |
Review the following work items for ${inputs.repo_name}:
${inputs.work_items}
Rules:
- Use gh for READ ONLY (view/list). Do NOT mutate GitHub.
- Implement local fixes in the worktree and commit them.
- Write ${inputs.worktree_path}/.ru/review-plan.json with your decisions,
including any proposed gh_actions (but do not execute them).
- If you need user input, ask via AskUserQuestion with clear options.
wait: user_interaction
timeout: 30m
on_question:
action: queue
priority: ${question.urgency:-normal}
metadata:
repo: ${inputs.repo_name}
worktree: ${inputs.worktree_path}
- id: finalize_artifacts
type: shell
depends_on: [review_issues_prs]
command: |
plan_path="${inputs.worktree_path}/.ru/review-plan.json"
digest_path="${inputs.worktree_path}/.ru/repo-digest.md"
if [[ ! -f "$plan_path" ]]; then
echo "Missing review-plan.json at $plan_path" >&2
exit 1
fi
if command -v jq >/dev/null 2>&1; then
if ! jq -e '.schema_version == 1 and (.repo | type=="string") and (.items | type=="array")' "$plan_path" >/dev/null 2>&1; then
echo "review-plan.json failed validation" >&2
exit 1
fi
fi
if [[ ! -f "$digest_path" ]]; then
echo "Missing repo digest at $digest_path" >&2
exit 1
fi
echo "Review artifacts ready for ${inputs.repo_name}" >&2
on_failure: warn
outputs:
plan_path: ${inputs.worktree_path}/.ru/review-plan.json
digest_path: ${inputs.worktree_path}/.ru/repo-digest.md
items_reviewed: ${steps.review_issues_prs.items_reviewed:-0}
outputs:
plan_path:
description: Path to review-plan.json
value: ${steps.finalize_artifacts.plan_path}
digest_path:
description: Path to repo-digest.md
value: ${steps.finalize_artifacts.digest_path}
items_reviewed:
description: Count of items reviewed
value: ${steps.finalize_artifacts.items_reviewed}
# Private repositories template
# Copy this to ~/.config/ru/repos.d/private.txt
# Add your private repos below
#
# Note: Private repos require authentication via gh CLI
# Run: gh auth login
# Or set: export GH_TOKEN=your_token
#
# Format is the same as public.txt:
# owner/repo
# owner/repo@branch
# owner/repo as local-name
# Example:
# mycompany/internal-tool
# mycompany/private-api
# Example public repositories
# Copy this file to ~/.config/ru/repos.d/repos.txt and customize
#
# Supported formats:
# https://github.com/owner/repo
# owner/repo (shorthand, assumes github.com)
# owner/repo@branch (pin to specific branch)
# owner/repo as local-name (custom local directory name)
#
# Lines starting with # are comments
# Empty lines are ignored
# Charmbracelet tools (beautiful terminal UIs)
charmbracelet/gum
charmbracelet/bubbletea
charmbracelet/lipgloss
# GitHub's official CLI
cli/cli
# Popular Bash utilities
koalaman/shellcheck
mvdan/sh
# Example with branch pinning
# owner/repo@develop
# Example with custom local name
# owner/repo as my-custom-name
MIT License (with OpenAI/Anthropic Rider)
Copyright (c) 2026 Jeffrey Emanuel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
ADDITIONAL RIDER / RESTRICTION (OpenAI / Anthropic):
This rider is part of the "conditions" of this License. In the event of any
conflict between this rider and any other portion of this License, this rider
controls.
"Restricted Parties" means OpenAI, L.L.C.; Anthropic, PBC; any of their
respective Affiliates; and any person or entity acting directly or indirectly
on behalf of, for the benefit of, or under the direction of any of the
foregoing (including any officer, director, employee, contractor, agent,
consultant, service provider, or representative).
Notwithstanding any other provision of this License, no rights are granted to
any Restricted Party. Any purported license, sublicense, assignment, transfer,
or other permission to any Restricted Party is null and void absent the
express prior written permission of Jeffrey Emanuel.
You may not provide, disclose, distribute, sublicense, sell, lease, lend,
host, make available, or otherwise permit access to the Software or any
derivative work of the Software (as defined in applicable copyright law)
(collectively, "Derivative Works") to or for any Restricted Party.
For purposes of this rider, "use" includes, without limitation: copying,
modifying, merging, publishing, distributing, sublicensing, selling,
transferring, making available, hosting, deploying, executing, benchmarking,
testing, analyzing, indexing, or incorporating the Software or any Derivative
Works into any dataset, training corpus, evaluation harness, or pipeline for
machine learning or other automated systems.
This rider applies to the Software and all Derivative Works. As a condition of
use, you agree that this rider is a precondition to exercising any rights
under this License, and you agree that any distribution of the Software or any
Derivative Works must include this rider provision unmodified.
Any breach of this rider automatically and immediately terminates the
permissions granted by this License. Upon termination, you must immediately
cease all use and distribution of the Software and any Derivative Works and
destroy all copies under your control.
You agree that a breach of this rider would cause irreparable harm and that
Jeffrey Emanuel may seek injunctive or other equitable relief to enforce this
rider, in addition to any other remedies available at law. To the maximum
extent permitted by applicable law, the prevailing party in any action to
enforce this rider shall be entitled to recover reasonable attorneys' fees and
costs.
For purposes of this rider, "Affiliate" means any entity that directly or
indirectly controls, is controlled by, or is under common control with the
specified party. "Control" means ownership of more than 50% of the voting
securities or other ownership interest, or the power to direct management or
policies by contract or otherwise.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"spawn_success": {
"success": true,
"session": "ru_sweep_test_12345",
"agents": [{"pane": "0.1", "type": "claude", "ready": true}]
},
"spawn_resource_busy": {
"success": false,
"error_code": "RESOURCE_BUSY",
"error": "session already exists"
},
"spawn_dependency_missing": {
"success": false,
"error_code": "DEPENDENCY_MISSING",
"error": "tmux not installed"
},
"wait_success": {
"success": true,
"condition": "idle",
"waited_seconds": 45.2
},
"wait_timeout": {
"success": false,
"error_code": "TIMEOUT",
"error": "Timeout waiting for condition"
},
"wait_agent_error": {
"success": false,
"error_code": "AGENT_ERROR",
"error": "Agent crashed or rate limited"
},
"activity_generating": {
"success": true,
"session": "test",
"state": "GENERATING",
"velocity": 150.5
},
"activity_idle": {
"success": true,
"session": "test",
"state": "WAITING",
"velocity": 0.0
},
"send_success": {
"success": true,
"delivered_to": 1,
"chunks": 1
},
"pane_output_with_commit_plan": {
"content": "Analyzing repository...\n\nRU_COMMIT_PLAN_JSON_BEGIN\n{\"commits\":[{\"files\":[\"src/main.py\"],\"message\":\"fix: resolve null pointer\"}],\"push\":true,\"excluded_files\":[],\"assumptions\":[],\"risks\":[]}\nRU_COMMIT_PLAN_JSON_END\n\nPlan generated."
},
"pane_output_with_release_plan": {
"content": "RU_RELEASE_PLAN_JSON_BEGIN\n{\"version\":\"1.2.0\",\"tag\":\"v1.2.0\",\"changelog_entry\":\"## v1.2.0\\n\\n### Fixed\\n- Bug fix\",\"version_files\":[{\"path\":\"VERSION\",\"old\":\"1.1.0\",\"new\":\"1.2.0\"}],\"checks\":[\"tests\"]}\nRU_RELEASE_PLAN_JSON_END"
}
}
#!/usr/bin/env bash
# Mock tmux for tests. Behavior controlled by NTM_MOCK_SCENARIO.
set -uo pipefail
scenario="${NTM_MOCK_SCENARIO:-ok}"
state_file="${NTM_MOCK_STATE_FILE:-/tmp/ntm_mock_state}"
load_session() {
if [[ -f "$state_file" ]]; then
head -n 1 "$state_file"
else
echo "test"
fi
}
emit_ok_output() {
cat <<'EOF'
I have read the AGENTS.md and README.md files carefully.
RU_UNDERSTANDING_JSON_BEGIN
{"summary":"Test repo for agent-sweep","conventions":["Bash 4.0+"],"risks":[],"notes":[]}
RU_UNDERSTANDING_JSON_END
Based on my analysis, here is the commit plan:
RU_COMMIT_PLAN_JSON_BEGIN
{
"commits": [
{"files": ["modified.txt"], "message": "fix: update test file\n\nUpdated the test file content."}
],
"push": false,
"excluded_files": [],
"assumptions": [],
"risks": []
}
RU_COMMIT_PLAN_JSON_END
EOF
}
emit_release_output() {
cat <<'EOF'
I have read the AGENTS.md and README.md files carefully.
RU_UNDERSTANDING_JSON_BEGIN
{"summary":"Test repo for agent-sweep","conventions":["Bash 4.0+"],"risks":[],"notes":[]}
RU_UNDERSTANDING_JSON_END
Based on my analysis, here is the commit plan:
RU_COMMIT_PLAN_JSON_BEGIN
{
"commits": [
{"files": ["modified.txt"], "message": "fix: update test file\n\nUpdated the test file content."}
],
"push": false,
"excluded_files": [],
"assumptions": [],
"risks": []
}
RU_COMMIT_PLAN_JSON_END
RU_RELEASE_PLAN_JSON_BEGIN
{
"version": "1.1.0",
"tag": "v1.1.0",
"changelog_entry": "## v1.1.0\n\n- Fixed test file",
"version_files": [{"path": "VERSION", "old": "1.0.0", "new": "1.1.0"}],
"checks": ["tests"]
}
RU_RELEASE_PLAN_JSON_END
EOF
}
cmd="${1:-}"
case "$cmd" in
capture-pane)
case "$scenario" in
ok)
emit_ok_output
;;
ok_with_release)
emit_release_output
;;
invalid_json)
cat <<'EOF'
RU_COMMIT_PLAN_JSON_BEGIN
{not valid json
RU_COMMIT_PLAN_JSON_END
EOF
;;
no_markers)
echo "Agent did not produce expected markers"
;;
*)
emit_ok_output
;;
esac
;;
list-panes)
format=""
while [[ $# -gt 0 ]]; do
if [[ "$1" == "-F" ]]; then
shift
format="${1:-}"
fi
shift || true
done
case "$format" in
*pane_pid*) echo "12345" ;;
*pane_id*) echo "0.1" ;;
*) echo "0.1" ;;
esac
;;
list-sessions)
session="$(load_session)"
echo "$session"
;;
has-session)
exit 0
;;
send-keys)
exit 0
;;
kill-session)
exit 0
;;
new-session)
exit 0
;;
*)
echo "mock tmux: unhandled args: $*" >&2
exit 2
;;
esac
1.3.1