Project Structure
Pyra is a Rust workspace with small, focused crates. Each crate has a clear responsibility boundary.
Crate layout
Section titled “Crate layout”Directorypyra-project/
- Cargo.toml workspace root
Directorycrates/
Directorypyra-cli/ CLI entrypoint, clap parsing, command dispatch
- …
Directorypyra-core/ shared context, paths, config, verbosity
- …
Directorypyra-errors/ shared error abstractions
- …
Directorypyra-project/ project logic, sync, lock, installer, environment
- …
Directorypyra-python/ Python version management
- …
Directorypyra-resolver/ dependency resolution (PubGrub-based)
- …
Directorypyra-ui/ terminal output, styles, JSON envelopes
- …
Directorydev-docs/ internal architecture docs
- …
Crate responsibilities
Section titled “Crate responsibilities”pyra-cli
Section titled “pyra-cli”The application entrypoint. Owns:
- clap struct/enum definitions (argument parsing)
- Command dispatch — routing parsed input to domain services
- Top-level error handling and exit code mapping
- Output mode selection (human vs JSON)
Key modules:
cli/— clap definitions (Cli,Command, argument structs)commands/— individual command handlers (one per command)lib.rs— entrypoint composition, error rendering, exit code normalization
pyra-core
Section titled “pyra-core”Shared runtime context and infrastructure. Owns:
AppContext— runtime paths, verbosity, configpaths.rs— centralized path resolution for Python store, environments, cacheconfig.rs— config loadingverbosity.rs— verbosity level modelerror.rs— core-level errors
All path resolution is centralized here. Other crates never build Pyra-managed paths independently.
pyra-errors
Section titled “pyra-errors”Shared error abstractions. Owns:
ErrorReport— structured error with summary, detail, and suggestionErrorKind— user / system / internal categorizationUserFacingErrortrait — contract for domain errors to produce user-facing reports
pyra-project
Section titled “pyra-project”The largest domain crate. Owns the full project lifecycle:
pyproject.rs— parsing and manipulation ofpyproject.tomlenvironment.rs— centralized environment managementidentity.rs— stable project identity from canonical rootinit.rs— project initializationservice.rs— command-level orchestration (sync, add, remove, run, etc.)doctor.rs— health diagnosticsoutdated.rs— upgrade reportingupdate.rs— lock refreshexecution.rs—pyra runexecution logicerror.rs— rich domain errors with typed categoriessync/— the sync subsystem:lockfile.rs— lock reading, writing, and freshnessinstall.rs— environment reconciliation and artifact managementselection.rs— group/extra selection logicproject_input.rs— dependency input normalizationmarker.rs— marker evaluation
pyra-python
Section titled “pyra-python”Python version management. Owns:
service.rs— install, uninstall, list, searchclient.rs— HTTP client for python-build-standalonestore.rs— local Python installation storageversion.rs— version parsing and matchinghost.rs— host platform detectionmodel.rs— Python version model
pyra-resolver
Section titled “pyra-resolver”Dependency resolution. Owns:
provider.rs— PubGrub dependency provider implementationsimple.rs— PyPI Simple API clientversion.rs— version compatibility and range logicmetadata.rs— distribution metadata parsingmarker.rs— PEP 508 marker evaluationmodel.rs— resolved package result typeserror.rs— resolution errors
pyra-ui
Section titled “pyra-ui”Terminal presentation. Owns:
terminal.rs— terminal rendering engineoutput.rs— output tree model, JSON envelope, status/exit formatting
The only crate that touches terminal formatting and styles.
Command flow
Section titled “Command flow”A typical command follows this path:
main.rsCli::parse()(pyra-cli: parse args)AppContext::discover()(pyra-core: build runtime context)commands::execute(command, &context)(pyra-cli: dispatch)pyra_project::service::*(pyra-project: domain logic)pyra_resolver::*(pyra-resolver: resolution (if needed))sync::lockfile::*(pyra-project: lock read/write)sync::install::*(pyra-project: environment reconciliation)
CommandEnvelope::from_execution()(pyra-ui: format result)terminal.render()orterminal.render_json()(pyra-ui: output)
Domain crates return typed results. The CLI crate maps those results into presentation output. Terminal formatting never happens inside domain logic.
Key dependencies
Section titled “Key dependencies”| Crate | Key dependencies |
|---|---|
pyra-cli | clap |
pyra-core | directories, camino |
pyra-errors | thiserror |
pyra-project | toml_edit, serde, sha2, tempfile |
pyra-python | reqwest, flate2, tar |
pyra-resolver | pubgrub, pep440_rs, pep508_rs, reqwest |
pyra-ui | anstream, serde_json |