A while ago I decided to learn some Rust. I bought a book, opened it months later and started a little side project: porting my R package saperlipopette to the terminal by writing a CLI with Rust. I then lost steam and threw the project away. Now I’m learning more Git with saperlipopette It makes me want to do the same outside of R, to reach more students. And in the meantime, even though I did conflicting feelings about this, I realized that using an LLM, specifically Claude Code (Opus 4.6), would help me get my CLI across the finish line!
Which my CLI already had
The CLI project already had a few exercises, all “Oh shit, Git!” exercises of saperlipopette. It had a bad name: ohcrabgit, a pun based on “Oh crap, Git!” and on Rust’s logo, which is a crab. Definitely not something you want to type into a terminal over and over again.
The interface was the following:
- You create an exercise in a folder by typing a command in the terminal.
- Then you open that folder and read the file
instructions.txtto know what to do, and then the filetip.txtin case you needed tips.
I wanted to keep that interface because it’s pretty simple and would work no matter what people usually use to work with Git. They must be using Git somewhere where they can read text files.
It had an internal infrastructure: for example, a file called git.rs that had some utility functions, such as init_playground or create_branch. It mainly used the Rustcrate git2 for the Git aspects.
Every line was painstakingly written by me, with the help of a search engine and the compiler’s helpful error messages. 😅
What I wanted for the CLI
I wasn’t that interested in writing Rust code anymore. Maybe one day that will be relevant to my work, but at the moment it is not. I wanted to grow the CLI to match the features of saperlipopette: more exercises and translations of the instructions/tips in French and Spanish. With that end product, I should be able to run the same workshops as before, but using the CLI instead of saperlipopette if my audience wasn’t just R users.
I also wanted to improve the formatting of the help and installation instructions.
The project went well! I have a Claude Code subscription, I call Claude from the terminal, from Positron IDE. Keep in mind that I hit the speed limit of a session right before it was time for my Pilates class, so it wasn’t that bad to just wait. 🧘
This is what was produced in it zut source codeand reviewed by me by the Rust newbie, therefore not extremely deep:
- Help formatting improvements. I reduced the ANSI strings in the code and requested more accessible colors (not sure if this is the best choice). Connect.
- I chose a better name for the CLI, the French curse word “zut” (“damn”). Claude did the renaming everywhere, which was mostly lazy of me. Connect.
- The installation instructions should now be executed
cargo install --git https://github.com/maelle/zutsuggestion from Claude, since the audience for my tool should be mainly developers. I guess I’ll see what the pain points are when people try to install it on different platforms… Connect. - The CLI now issues instructions and tips in different languages, based on the system locale, an environment variable, or a flag. I requested to use the system locale as default. In that same workflow, Claude added more unit tests, which I didn’t even ask for, and integration tests, which I did ask for after I saw the tests folder was empty. Connect
- All the new exercises from saperlipopette have been ported to zut in French, English and Spanish, and they are categorized in the help output and in the documents (which at the moment is… the README). I tried running them, which led to small adjustments (empty lines at the end of files) and larger adjustments (e.g. in the git bisect exercise in saperlipopette you ran an R script, but it had to become a shell script to make it meaningful in zut). Connect.
- A bug fix, as it only worked… from the source code folder. 🤦 Connect.
The state of Zut
Install Zut:
cargo install --git https://github.com/maelle/zut
View help:
zut --help
whose output is:
Create example Git messes to solve, inspired by https://ohshitgit.com/ Usage: zut[TARGET]. In the exercise folder, open instructions.txt. Arguments: Name of the exercise Possible values: - time-machine: Oh shit, I did something terribly wrong, please tell me git has a magic time machine!?! - small-change: Oh shit, I committed and immediately realized I need to make one small change! - latest-message: Oh shit, I need to change the message on my last commit! - committed-to-main: Oh shit, I accidentally committed something to main that should have been on a brand new branch! - committed-to-wrong: Oh shit, I accidentally committed to the wrong branch! - undo-commit: Oh shit, I need to undo a commit from like 5 commits ago! - undo-file: Oh shit, I need to undo my changes to a file! - split-changes: Hey I'd like to split these changes to the same file into several commits! - clean-dir: Hey, how do I remove all my debugging left-over stuff at once? - conflict: Hey I'd like to see what merge conflicts look like! - rebase-i: Hey I'd like to make my commits in a branch look informative and smart! (interactive rebase) - reset: Hey I'd like to restart from scratch and reorganize my commits! (git reset --mixed) - bisect: Hey I'd like to find which commit introduced a bug! - log-deleted-file: I want to find which commit deleted a file! - log-deleted-line: I want to find which commit deleted a line! - revparse: I want to understand ancestry references like HEAD~5 and HEAD^^! - blame: I want to find who added a specific line and when! - worktree: I need to see what the project looked like at a certain version! [TARGET] Where to create the exercise directory. Default: temporary directory [default: tempdir] Options: --lang Language (default: auto-detected from system locale) [possible values: en, fr, es] -h, --help Print help (see a summary with '-h') -V, --version Print version Examples: zut small-change creates the small-change exercise folder in a temporary folder. zut latest-message .. creates the latest-message exercise folder in the parent of the current folder. Categories: Oh shit, Git!: time-machine, small-change, latest-message, committed-to-main, committed-to-wrong, undo-commit, undo-file Clean history: split-changes, clean-dir, conflict, rebase-i, reset Use history: bisect, log-deleted-file, log-deleted-line, revparse, blame, worktree
To create the time machine exercise in a temporary folder:
zut time-machine
The path to the folder is printed on the screen so you can open and read it instructions.txt there and get started: in that challenge a git reset --hard too many have been performed so you need it git reflog to save an important commit.
To create the debt exercise in a folder above the current one, in French:
zut blame .. --lang fr
In that challenge you have to find out who wrote a certain line in a script. Dr. Jekyll or Mr. Hyde? git blame will help!
Last but not least, if you’re trying to create an exercise somewhere where it exists:
zut blame .. --lang fr
you get:
Exercise folder already exists: ../exo-blame — delete it or choose a different target.
Conclusion: future work
Using Claude Code I was able to port the functions of the saperlipopette R package to the zut CLI. The next steps are for me to actually use zut beyond the testing I’ve done to troubleshoot further issues. Tell me to teach “Painlessly improve your Git history” again, I would do all the exercises back to back again. I would do that in the human language of the workshop.
I could also improve the CLI’s code based on user feedback and based on feedback from Claude Code for example using the posit-dev/critical-code-reviewer-skill (thanks to Mon because you told me about it!). The documentation could also use some work, compared to saperlipopette, but as a supplement to workshops it can be fine.
The Saperlipopette package itself has been submitted rOpenSci software peer review so I expect it will change for the better. If I need to transfer those changes, depending on what they are, I might resort to Claude Code again.
Related
#Zut #Git #saperlipopette #port #terminal #Claude #bloggers

