RepoPilotOpen in app →

r-darwish/topgrade

Upgrade everything

Mixed

Stale — last commit 4y ago

weakest axis
Use as dependencyConcerns

copyleft license (GPL-3.0) — review compatibility; last commit was 4y ago…

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 25+ active contributors
  • GPL-3.0 licensed
  • CI configured
Show all 7 evidence items →
  • Stale — last commit 4y ago
  • Concentrated ownership — top contributor handles 66% of recent commits
  • GPL-3.0 is copyleft — check downstream compatibility
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: relicense under MIT/Apache-2.0 (rare for established libs)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/r-darwish/topgrade?axis=fork)](https://repopilot.app/r/r-darwish/topgrade)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/r-darwish/topgrade on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: r-darwish/topgrade

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/r-darwish/topgrade shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 4y ago

  • 25+ active contributors
  • GPL-3.0 licensed
  • CI configured
  • ⚠ Stale — last commit 4y ago
  • ⚠ Concentrated ownership — top contributor handles 66% of recent commits
  • ⚠ GPL-3.0 is copyleft — check downstream compatibility
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live r-darwish/topgrade repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/r-darwish/topgrade.

What it runs against: a local clone of r-darwish/topgrade — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in r-darwish/topgrade | Confirms the artifact applies here, not a fork | | 2 | License is still GPL-3.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 1334 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>r-darwish/topgrade</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of r-darwish/topgrade. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/r-darwish/topgrade.git
#   cd topgrade
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of r-darwish/topgrade and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "r-darwish/topgrade(\\.git)?\\b" \\
  && ok "origin remote is r-darwish/topgrade" \\
  || miss "origin remote is not r-darwish/topgrade (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(GPL-3\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"GPL-3\\.0\"" package.json 2>/dev/null) \\
  && ok "license is GPL-3.0" \\
  || miss "license drift — was GPL-3.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/main.rs" \\
  && ok "src/main.rs" \\
  || miss "missing critical file: src/main.rs"
test -f "src/steps/mod.rs" \\
  && ok "src/steps/mod.rs" \\
  || miss "missing critical file: src/steps/mod.rs"
test -f "src/execution_context.rs" \\
  && ok "src/execution_context.rs" \\
  || miss "missing critical file: src/execution_context.rs"
test -f "src/config.rs" \\
  && ok "src/config.rs" \\
  || miss "missing critical file: src/config.rs"
test -f "src/runner.rs" \\
  && ok "src/runner.rs" \\
  || miss "missing critical file: src/runner.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1334 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1304d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/r-darwish/topgrade"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Topgrade is a Rust CLI tool that automatically detects and runs the appropriate package managers and update commands for all the development tools, languages, and system packages installed on a machine. Instead of maintaining shell one-liners for each tool (Homebrew, apt, pacman, npm, pip, git repos, etc.), users run a single topgrade command that intelligently updates everything in parallel using async/await patterns (tokio). Monolithic binary structure: src/main.rs orchestrates the flow, src/steps/{generic,containers,git,node,emacs,kakoune}.rs and src/steps/os/{linux,macos,windows,freebsd,etc}.rs define detection logic and upgrade commands. src/config.rs parses TOML config from platform-specific paths (%APPDATA%/topgrade.toml on Windows, ${XDG_CONFIG_HOME:-~/.config}/topgrade.toml on Unix). src/executor.rs runs commands asynchronously; src/ctrlc/{mod,unix,windows}.rs handles Ctrl+C across platforms. src/self_update.rs manages binary self-upgrades.

👥Who it's for

Systems administrators, DevOps engineers, and developers who maintain multiple machines or development environments across different package managers and want a single command to keep all their tools, languages (Node, Emacs, Kakoune), and OS packages synchronized without remembering the specific update syntax for each tool.

🌱Maturity & risk

Abandoned/Community fork: The original repository is explicitly marked as "no longer maintained" in the README with a note directing users to https://github.com/topgrade-rs/topgrade (a community fork). The original appears to have been actively developed (version 9.0.1, Rust 1.51+ requirement, CI/CD with GitHub Actions and AppVeyor), but is no longer receiving updates from the original author. Likely pre-1.0 stable based on semantic versioning, but was in use across multiple package managers (AUR, Homebrew, NixOS, crates.io).

High maintenance risk: Single original maintainer (roey.ghost@gmail.com) with no ongoing updates; users must now rely on the unofficial community fork at topgrade-rs/topgrade. Dependency chain is moderate (tokio, serde, clap, regex, sys-info, semver) but feature-complete for a CLI tool. Platform-specific fragmentation across OS modules (src/steps/os/{archlinux,macos,freebsd,android,etc}) means bugs in one OS won't catch regressions in others. Self-update mechanism adds complexity (self_update_crate with feature gates for Windows zip vs Unix tar).

Active areas of work

The original repo is not actively maintained. The README explicitly states the original author is stepping back; the community fork at https://github.com/topgrade-rs/topgrade is the active project. No new commits expected in r-darwish/topgrade. Users should migrate to the community-maintained version for ongoing support.

🚀Get running

# Clone the original (unmaintained) repo
git clone https://github.com/r-darwish/topgrade.git
cd topgrade

# Build with Rust (requires Rust 1.51+)
cargo build --release

# Or install directly from crates.io (but see abandonment note)
cargo install topgrade

# Run the binary
./target/release/topgrade

Note: For active development and maintenance, use the community fork instead: git clone https://github.com/topgrade-rs/topgrade.git

Daily commands:

# Development build
cargo build

# Run with debug logging
RUST_LOG=debug ./target/debug/topgrade

# Run with config file
./target/debug/topgrade --config ~/.config/topgrade.toml

# Dry-run to see what would be upgraded
./target/debug/topgrade --no-retry

# See all flags
./target/debug/topgrade --help

🗺️Map of the codebase

  • src/main.rs — Entry point and CLI argument parsing; defines the primary upgrade workflow orchestration
  • src/steps/mod.rs — Core abstraction for all upgrade steps; every contributor must understand the Step trait and execution model
  • src/execution_context.rs — Shared state and environment passed through the upgrade pipeline; critical for understanding cross-step data flow
  • src/config.rs — Configuration parsing and validation; defines how users customize the upgrade behavior
  • src/runner.rs — Executes upgrade steps sequentially and manages step ordering logic
  • src/executor.rs — Low-level command execution abstraction; handles spawning external processes and capturing output
  • src/steps/os/mod.rs — Platform-specific OS upgrade logic dispatcher; shows how topgrade abstracts over Linux, macOS, Windows, BSD

🧩Components & responsibilities

  • CLI (main.rs, clap) (clap, log, pretty_env_logger) — Parse command-line arguments, initialize logging, validate config file path, invoke runner
    • Failure mode: Invalid arguments or missing config file causes early exit with usage error
  • Config system (config.rs) — Load TOML file, deserialize into Config struct, validate and transform user settings

🛠️How to make changes

Add a new OS upgrade step

  1. Create a new file in src/steps/os/ (e.g., src/steps/os/openbsd.rs) with a function implementing OS-specific upgrades (src/steps/os/openbsd.rs)
  2. Add the module declaration to src/steps/os/mod.rs and implement the platform detection logic (src/steps/os/mod.rs)
  3. Define the upgrade function returning a Step struct that wraps command execution (src/steps/os/openbsd.rs)

Add a new language package manager step

  1. Create src/steps/python.rs (or similar) with a function returning a Step for upgrading Python packages (src/steps/python.rs)
  2. Register the step in src/steps/mod.rs by adding it to the get_steps() function conditional logic (src/steps/mod.rs)
  3. Optionally add configuration options in config.rs to allow users to enable/disable this step (src/config.rs)

Add a custom configuration option

  1. Define a new field in the Config struct in src/config.rs with serde attributes for TOML parsing (src/config.rs)
  2. Add documentation and example in config.example.toml (config.example.toml)
  3. Use the config field in step implementations to conditionally enable features (src/steps/mod.rs)

Add support for a new platform

  1. Create src/steps/os/newplatform.rs with platform detection and upgrade commands (src/steps/os/newplatform.rs)
  2. Add a module declaration in src/steps/os/mod.rs and update the platform matching logic (src/steps/os/mod.rs)
  3. Test on the target platform and document in README.md (README.md)

🔧Why these technologies

  • Rust + cargo — Systems language with zero-cost abstractions; enables cross-platform compilation and efficient process spawning
  • clap (derive macros) — Declarative CLI argument parsing with automatic help generation and validation
  • TOML config format — Human-friendly configuration format for specifying which upgrade steps to enable/disable
  • thiserror + custom Error enum — Structured error handling with context preservation across step failures
  • walkdir + glob — Efficient file discovery for finding package manager configs and custom upgrade paths

⚖️Trade-offs already made

  • Sequential step execution instead of parallel

    • Why: Simplifies error handling and ensures predictable ordering; some upgrades depend on earlier ones (e.g., OS packages before language tools)
    • Consequence: Total upgrade time is sum of all steps; cannot leverage multi-core machines for independent upgrades
  • Trait-based step abstraction instead of scripting

    • Why: Type-safe, compile-time checked, easier to maintain than shell/Lua scripting; allows conditional logic based on environment
    • Consequence: Adding new steps requires code changes and recompilation; steeper barrier than config-only customization
  • Single config file per system instead of per-step configs

    • Why: Centralized configuration; easier for users to understand global behavior
    • Consequence: Less granular per-tool customization; adds complexity to config parsing if many options needed

🚫Non-goals (don't propose these)

  • Does not provide real-time monitoring or progress bars during command execution
  • Does not handle authentication for package managers (assumes passwordless sudo or pre-authenticated credentials)
  • Does not manage conflicting versions across ecosystems (delegates to individual package managers)
  • Does not support rolling back failed upgrades automatically
  • Does not sync configuration across multiple machines (single-machine operation)

🪤Traps & gotchas

  1. Self-update feature is opt-in: Requires --features self-update at compile time; binaries released via crates.io ship with this enabled, but developers must explicitly enable it or users won't get auto-upgrade. 2. Platform-conditional dependencies: nix crate (Unix only), winapi (Windows only)—don't assume cross-platform buildability without explicit cfg gates. 3. Config path is platform-specific and unobvious: Windows uses %APPDATA%/topgrade.toml (environment variable, not literal path), Unix uses XDG_CONFIG_HOME or ~/.config/topgrade.toml—directory.rs handles this but users must know to look there. 4. Remote execution via SSH: remote_topgrades config key enables SSH to remote hosts; this requires SSH keys, passwordless login, or SSH agent setup—not documented in code comments. 5. Self-renaming on update: src/self_renamer.rs swaps the binary in-place; on Windows this may fail if the file is locked by running processes or antivirus; on Unix it's atomic but requires write permissions to the binary location.

🏗️Architecture

💡Concepts to learn

  • Async/await with Tokio runtime — Topgrade runs multiple package managers in parallel (npm, apt, brew, pacman simultaneously) without blocking; understanding tokio::spawn, futures, and multi-threaded executors explains why updates feel fast
  • Platform conditional compilation (cfg!) — Topgrade detects Windows vs Unix at compile time and includes only relevant dependencies (winapi, nix) in each binary; misunderstanding cfg! leads to impossible-to-debug platform-specific bugs
  • Self-updating executables — Topgrade updates itself via self_update_crate by downloading a new binary and atomically replacing the running process; this is non-trivial on Windows (file locks) vs Unix (atomic rename)
  • XDG Base Directory specification — Config files live at ${XDG_CONFIG_HOME:-~/.config}/topgrade.toml on Unix; topgrade must respect this standard or users with custom XDG setups won't find their configs
  • Signal handling (SIGINT/SIGTERM) across platforms — src/ctrlc/ implements graceful shutdown on Ctrl+C without leaving zombie subprocesses; Unix (nix crate) and Windows (ctrlc-console API) require different mechanisms
  • Semver parsing and version comparison — Topgrade detects installed tool versions (e.g., npm --version → v16.0.0) and compares them against remote registries to decide if upgrades are available; the semver crate provides ordering semantics
  • SSH remote command execution and automation — The remote_topgrades config feature SSHes into other hosts and runs topgrade remotely before updating the local machine; this requires shell escaping, exit code handling, and error propagation across the network
  • topgrade-rs/topgrade — The active community fork; all ongoing development and bug fixes happen here after the original author stepped back
  • sharkdp/bat — Similar ecosystem-scanning tool written in Rust; uses clap for CLI parsing and demonstrates modern Rust patterns applicable to topgrade
  • BurntSushi/ripgrep — High-performance Rust CLI tool with excellent documentation and cross-platform async patterns (similar to topgrade's tokio usage)
  • cargo-install-upgrade/cargo-update — Complementary tool for upgrading Rust binaries installed via cargo; topgrade calls this indirectly but cargo-update solves the same problem for Rust-only workflows
  • nix-community/nix-shell-utils — NixOS-specific package management companion; topgrade includes NixOS support but this repo explores declarative dev environments as an alternative upgrade strategy

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for OS-specific upgrade steps

The repo has comprehensive OS support (Arch, Debian, Fedora, macOS, etc.) across src/steps/os/ but no visible test coverage. Given the critical nature of system package manager interactions and the variety of OS configurations, integration tests would catch regressions early and give contributors confidence when modifying os-specific logic.

  • [ ] Create tests/integration/ directory structure
  • [ ] Add test cases in tests/os_steps.rs for each OS module (src/steps/os/archlinux.rs, src/steps/os/macos.rs, etc.)
  • [ ] Mock file system and command execution using tempfile and assert_cmd crates
  • [ ] Test detection logic (e.g., os_release parsing) and upgrade command generation
  • [ ] Add test execution to .github/workflows/main.yml

Refactor src/steps/mod.rs to extract step definitions into individual modules

The src/steps/mod.rs likely contains large match statements or enum definitions coordinating 15+ different upgrade steps (containers, emacs, git, node, kakoune, generic, etc.). This makes the file hard to navigate and complicates adding new steps. Breaking step registration/execution into a trait-based system would improve maintainability.

  • [ ] Create src/steps/step_trait.rs defining a Step trait with execute() and detect() methods
  • [ ] Convert existing step implementations (containers.rs, emacs.rs, git.rs, node.rs, kakoune.rs) to implement this trait
  • [ ] Refactor src/steps/mod.rs to use a registry pattern (e.g., Vec<Box<dyn Step>>)
  • [ ] Update src/main.rs or src/runner.rs to iterate over registered steps instead of match statements
  • [ ] Verify all existing functionality via cargo test

Add comprehensive documentation and examples for custom step configuration

The config.example.toml exists but there's no visible guide in doc/ explaining how users can write custom upgrade steps or extend topgrade. Given that generic.rs exists and supports custom commands, documenting this extensibility would help the community contribute custom integrations and reduce maintenance burden on core maintainers.

  • [ ] Create doc/CUSTOM_STEPS.md explaining the generic step configuration
  • [ ] Add 3-5 real-world examples in doc/CUSTOM_STEPS.md (e.g., upgrading Python packages, Rust tools, custom shell scripts)
  • [ ] Update config.example.toml with inline comments explaining each section's purpose
  • [ ] Add a 'Configuration' section to README.md linking to CUSTOM_STEPS.md
  • [ ] Reference this documentation in .github/ISSUE_TEMPLATE/feature_request.md to guide users toward self-service customization

🌿Good first issues

  • Add tests for src/config.rs: Currently no visible test/ directory in the file list. Write unit tests for TOML parsing (valid config, missing fields, invalid values) and platform-specific path resolution (Windows %APPDATA%, Unix XDG_CONFIG_HOME fallback): Config parsing is critical and handles platform differences; bugs here silently use wrong settings
  • Document the remote execution feature: src/config.rs and config.example.toml reference remote_topgrades but there's no docstring or usage example. Add comments explaining SSH key setup, execution order, and the --remote-host-limit flag: This feature is powerful but opaque; even developers won't discover it without docs
  • Add support for detecting and updating custom or missing package managers: Create a generic plugin/hook system in src/steps/mod.rs that allows users to define custom upgrade commands in TOML config (like a [[custom_steps]] section with detect_cmd and upgrade_cmd). Reference src/steps/generic.rs for pattern: Many users have language-specific tools (Rust toolchains, Go, Elixir) not yet covered by hardcoded steps; custom steps would unlock extensibility without code changes

Top contributors

Click to expand

📝Recent commits

Click to expand
  • cc7e607 — Archive (r-darwish)
  • 06a55ed — fix-pnpm (#1020) (kothavade)
  • a5e0128 — Update bug_report.md with improved hints (#971) (xeruf)
  • f390f2e — Ensure selfupdate is enabled for SDKMAN! (#954) (qcloutier)
  • d864199 — Add Pamac support (#953) (Spaceface16518)
  • 4e6f48c — Sparkle for updates (#950) (r-darwish)
  • 4a7de60 — npm/cli 8.11.0 deprecated -g flags (#949) (Mark Nefedov)
  • 717674e — Bump (r-darwish)
  • abdd1db — Don't try to update devcontainers (#946) (r-darwish)
  • 2585156 — Stop using packages.el (#942) (r-darwish)

🔒Security observations

  • High · Outdated tokio Dependency — Cargo.toml - tokio = { version = "1.5.0", features = ["process", "rt-multi-thread"] }. The tokio dependency is pinned to version 1.5.0, which is significantly outdated. This version was released in September 2021 and likely contains known security vulnerabilities that have been patched in newer versions. Fix: Update tokio to the latest stable version (currently 1.x). Run 'cargo update' and verify all security patches are applied.
  • High · Outdated chrono Dependency — Cargo.toml - chrono = "0.4.19". The chrono dependency is pinned to version 0.4.19 (November 2020), which is significantly outdated. Recent versions of chrono have had security issues related to parsing and time handling. Fix: Update chrono to version 0.4.24 or later. This is critical for time-based security operations.
  • High · Outdated regex Dependency — Cargo.toml - regex = "1.5.3". The regex dependency is pinned to version 1.5.3, which is outdated. Regex parsing can have security implications if used for input validation. Fix: Update regex to the latest version (currently 1.x). Run 'cargo update' to pull in security patches.
  • Medium · Outdated serde Dependency — Cargo.toml - serde = { version = "1.0.125", features = ["derive"] }. The serde dependency is pinned to version 1.0.125, which is outdated. While serde is generally stable, newer versions may include security hardening. Fix: Update serde to the latest version in the 1.x series to ensure security patches are applied.
  • Medium · Outdated toml Dependency — Cargo.toml - toml = "0.5.8". The toml dependency is pinned to version 0.5.8 (2021). TOML parsing can be security-sensitive when handling untrusted configuration files. Fix: Update toml to version 0.5.11 or later (or evaluate toml_edit for more robust parsing).
  • Medium · Outdated clap Dependency — Cargo.toml - clap = { version = "3.1", features = ["cargo", "derive"] }. The clap dependency is pinned to version 3.1, which is outdated. Newer versions in the 4.x series have improved security and parsing. Fix: Update clap to version 4.x for improved security and features.
  • Medium · Outdated log and pretty_env_logger — Cargo.toml - log = "0.4.14" and pretty_env_logger = "0.4.0". Logging dependencies are outdated (log 0.4.14, pretty_env_logger 0.4.0 from 2021). While logging itself may not be a direct security risk, outdated logging can miss important security events. Fix: Update to the latest versions: log to 0.4.20+ and pretty_env_logger to 0.5.0+.
  • Medium · Outdated nix Dependency — Cargo.toml - nix = "0.24.1" (Unix-only dependency). The nix crate is pinned to version 0.24.1. Given that nix provides Unix system interface bindings, outdated versions may lack security-relevant syscall updates. Fix: Update nix to the latest version (currently 0.27.x or higher). This is important for Unix security syscalls.
  • Medium · Project No Longer Maintained — README.md. According to the README, this repository is no longer maintained by the original author. This means security vulnerabilities and bugs will not receive official patches. Fix: Consider migrating to the community-maintained fork at https://github.com/topgrade-rs/

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · r-darwish/topgrade — RepoPilot