Getting started
Fork the repository
Fork Rehanasharmin/Progflow on GitHub, then clone your fork:git clone https://github.com/<your-username>/Progflow.git
cd Progflow
Build and verify
cargo build --release
./target/release/progflow --help
See Building from source for full prerequisites and install steps.Create a branch
git checkout -b my-feature
Adding a new command
Each command lives in its own file under src/commands/. The pattern is consistent across all existing commands.
Create the command module
Add src/commands/<name>.rs with a pub fn run function that returns Result<(), AppError>:// src/commands/yourcommand.rs
use crate::error::AppError;
pub fn run(name: &str) -> Result<(), AppError> {
// implementation
Ok(())
}
Export the module
Add a pub mod line to src/commands/mod.rs: Add a variant to the Commands enum
Open src/main.rs and add your variant to the Commands enum:#[derive(Subcommand)]
enum Commands {
// ... existing variants ...
#[command(about = "Description of your command")]
Yourcommand { name: String },
}
Dispatch in main
Add a match arm in the match cli.command block in main():Commands::Yourcommand { name } => yourcommand::run(&name),
Import your new module at the top of main.rs alongside the other command imports:use commands::{edit, list, new, note, off, on, yourcommand};
Error handling
Use the variants of AppError (defined in src/error.rs) to signal different failure modes:
| Variant | Exit code | When to use |
|---|
AppError::User(String) | 1 | Bad arguments, flow not found, or any user-fixable problem |
AppError::Io(String, std::io::Error) | 2 | File read/write failures — include the file path as the first argument |
AppError::Json(String, serde_json::Error) | 2 | JSON parse or serialization failures — include the file path as the first argument |
// User error — describes what the user did wrong
return Err(AppError::User(format!("Flow '{}' does not exist", name)));
// IO error — wraps the underlying std::io::Error with context
fs::read_to_string(&path).map_err(|e| AppError::Io(path.display().to_string(), e))?;
// JSON error — wraps serde_json::Error with context
serde_json::from_str(&content).map_err(|e| AppError::Json(path.display().to_string(), e))?;
Error messages are printed to stderr by main() automatically — your command only needs to return the error.
Code style and checks
Run these commands before committing:
cargo fmt # Format code
cargo clippy # Lint for common mistakes
cargo test # Run unit tests
cargo clippy treats warnings as guidance, not hard failures, but address any new warnings introduced by your change before opening a pull request.
Submitting a pull request
Push your branch
git push origin my-feature
Describe your change
In the pull request description, explain:
- What the change does
- Why it is needed or useful
- Any edge cases or platform-specific behaviour to be aware of