iRODS Consortium internship
iRODS Client
System Tray
A cross-platform desktop app that watches local folders and moves new research data into iRODS, without asking every user to become a command-line operator.
Built for the people next to the instrument
Bring automated ingest to people who don’t live in a terminal.
iRODS Automated Ingest is powerful, but it assumes someone comfortable on the command line. The people producing the data often aren’t: a researcher whose instrument writes images all day, or lab staff on a shared workstation. Terrell Russell and Kory Draughn at the iRODS Consortium asked the three of us to close that gap with a desktop app.
The app is meant to stay out of the way. You sign in, map a local folder to an iRODS collection, and it uploads new files from the tray. By default it deletes the local copy afterward so the instrument’s machine doesn’t fill up, but each folder can keep files, send them to the trash, or move them elsewhere.
“Pick a folder, drop files in, and they land in iRODS.”
The first month went into deciding what to build
Agree on the product before writing it.
The three of us spent the start of the internship on design, not code. Together we wrote the decision records that set the product’s direction and its stack, weighing C++/Qt, pystray, wxWidgets, C#/.NET, and Rust before choosing Python, PySide6, and Watchdog. Then we broke the app into GitHub issues that anyone on the team could pick up.
Building went smoothly because of it. By the time we were writing features, most questions about scope and how failures should behave already had answers the team had agreed on.
Every feature started as an issue
How the work moved.
No feature belonged to one person. Whoever picked up an issue built it and took the pull request through review with Terrell and Kory. Besides my own issues, I did much of the team’s triage, sorting new issues as they came in and reviewing my co-interns’ pull requests.
Agree on direction
Write down product scope and stack choices before the first feature.
Split the work into issues
Every feature or bug becomes an issue anyone on the team can pick up.
Review everything
Every pull request is triaged and reviewed by the team, then by iRODS staff.
Test at the seams
Stub the iRODS session, render Qt offscreen, and keep live-server tests opt-in.
Where my own pull requests landed
The layers underneath the features.
Most of the pull requests I wrote myself touched code that the rest of the app sits on.
Adaptive theming
Every hardcoded style moved into one theme template. A single set of iRODS brand colors drives the stylesheet and the Qt palette, and follows the OS light/dark setting live.
Text scaling for accessibility
Font sizes were fixed in pixels, so raising the OS text size left headings and lists small. They now derive from the system font, so people who need larger text get it everywhere.
Test foundation
The project’s first test suite: 105 tests at 86% line coverage, aimed at mistakes that are costly and hard to catch by hand, like a file landing in the wrong collection.
What the tests caught
A folder set to move files after upload, with no destination, would build a path from the working directory. I traced it and fixed it in the upload worker.
Where it ended up
Released on PyPI, with the tests running in CI.
On August 23, Terrell published the first release to PyPI and wired the test suite into GitHub Actions, where it has grown from 105 to 123 tests. I came out of the summer with a different idea of when something is done. I used to stop once the main path worked. Now I also ask whether the next person can change the code and find out from the tests what they broke.
What’s still open
The gaps we know about.
These are the problems I would pick up first. The first three are filed as issues, and the testing gaps were written up in the original test pull request.
A queue that survives a restart
Pending uploads live only in memory. Quitting drops them, nothing rescans on startup, and users can’t see or cancel what’s waiting.
Files still being written
The worker waits about three seconds for a file to stop growing, then uploads anyway. Slow instruments need a configurable settle period.
More than one upload at a time
Transfers run one by one on a single worker thread, so one large file holds up everything behind it.
Tests against real timing
The login thread, the live Watchdog observer, and uploads to a real zone still need tests that run outside stubs.