Architecture
Cursus is a Rust CLI application built with clap for argument parsing and ratatui for terminal UI. This page gives a high-level tour of the codebase — for detailed design rationale, see the Architecture Decision Records.
Module overview
Section titled “Module overview”| Module | Responsibility |
|---|---|
src/cli/ | clap-based CLI with global flags and subcommands |
src/tui/ | Interactive terminal UI wizards (ratatui/crossterm) |
src/model/ | Core domain types: config, changesets, changelogs |
src/package_manager/ | Adapter trait for Cargo and npm workspace enumeration, versioning, and publishing |
src/git/ | Git lifecycle management (commit, tag, push, branch) |
src/github/ | GitHub API integration (releases, PRs, asset uploads) |
src/command/ | CommandRunner trait for shell command execution with dry-run support |
src/env.rs | Dependency injection and runner composition |
src/conventional_commit.rs | Conventional Commit parser |
src/path.rs | AbsolutePath newtype for validated absolute paths |
Key patterns
Section titled “Key patterns”Package manager adapters
Section titled “Package manager adapters”The PackageManagerAdapter trait provides a uniform interface across package managers:
enumerate_projects()— discover packages and their current versionswrite_version()— update a package’s version in its manifest; returnsVec<PathBuf>of the files actually modified (which may be the workspace-root manifest rather than the package’s own, e.g. for Cargo crates usingversion.workspace = true); callers must stage those paths for gitupdate_dependency_version()— update an intra-workspace dependency’s pinned version; also returnsVec<PathBuf>of modified files for git stagingupdate_lock_file()— regenerate the lock file after version changespublish()— publish a package to its registryregistry_name()— display name for the registry
TUI wizards
Section titled “TUI wizards”Each TUI wizard follows a consistent pattern:
- A
Screenenum tracks the current state - A pure
handle_key()function handles state transitions (testable without a terminal) - Separate
ui()/render_*()functions handle rendering
Git ref validation
Section titled “Git ref validation”Every GitWorkdir method that accepts a caller-supplied branch name, tag name, or revision string passes it through the appropriate validator in the git::ref_format submodule (validate_branch_name, validate_tag_name, validate_revision) before invoking the CommandRunner. Any new git operation that takes such a string must do the same.
Command execution
Section titled “Command execution”The CommandRunner trait abstracts shell command execution. The DryRunCommandRunner decorator wraps any runner and intercepts commands that would mutate state, logging them instead — implementing a late-guard dry-run pattern.
Error handling
Section titled “Error handling”Cursus uses anyhow::Result throughout. Production code never panics — all errors are propagated with .context() or bail!().
API reference
Section titled “API reference”For detailed type-level documentation, see the rustdoc on docs.rs.