How Worktrunk Handles Network Requests for CI Status and PR Details
Worktrunk retrieves CI status and PR details by lazily launching background CLI commands that query GitHub or GitLab, caching results atomically to disk, and updating the UI via file-system events without blocking the main thread.
Worktrunk (max-sixty/worktrunk) is a Rust-based CLI tool for managing Git worktrees that displays real-time CI badges and pull request metadata. To maintain interface responsiveness while fetching remote data, it implements a cache-first, non-blocking architecture that delegates network requests to platform-specific CLI tools and hydrates the UI asynchronously.
The Cache-First Data Flow
When rendering a list of worktrees with CI badges, Worktrunk follows a five-step pipeline that prioritizes local data before hitting the network.
Step 1: Local Cache Lookup
Before spawning any network requests, Worktrunk checks a file-based cache located at .git/wt/cache/ci-status/<branch>.json. The cache implementation in src/cache.rs attempts to load existing CI data:
let ci = CiCache::load(branch)?;
if let Some(entry) = ci {
// Use cached CI info immediately
render_ci(entry);
}
If the cache entry exists, Worktrunk renders the CI status instantly. This lookup occurs in the main rendering path, ensuring the first frame of any command (e.g., wt list) displays before any network request completes.
Step 2: Background Command Execution
When the cache misses, Worktrunk spawns a background process to fetch fresh data. In src/output/concurrent.rs, the Cmd wrapper executes forge-specific CLI tools—gh for GitHub or glab for GitLab—decoupled from the main thread:
let cmd = Cmd::new("gh")
.args(["pr", "list", "--json", "number,title,author,headRefOid"])
.current_dir(&repo_path)
.scrub_git_discovery_env()
.run();
The Cmd::new(...).run() method captures stdout/stderr while allowing the UI to continue rendering, preventing network latency from freezing the picker interface.
Step 3: Structured JSON Parsing
Worktrunk requests machine-readable JSON via the --json flag rather than parsing human-readable text, eliminating locale-dependent fragility. The picker logic in src/picker/prs.rs deserializes the output into internal structs:
let pr_info: Vec<PrInfo> = serde_json::from_slice(&cmd.stdout)?;
This structured approach ensures consistent parsing across different GitHub/GitLab versions and user locales.
Step 4: Atomic Cache Persistence
After parsing, Worktrunk writes the data atomically to prevent corruption during concurrent access. The write_atomically function in src/utils.rs (lines 149-158) ensures the cache file is written completely or not at all:
write_atomically(&cache_path, serde_json::to_vec(&pr_info)?)?;
The atomic write guarantees that subsequent cache reads never encounter partial JSON, even if the process terminates mid-write.
Step 5: Event-Driven UI Refresh
Worktrunk monitors the cache directory using the notify crate (Linux/macOS) to detect when background writes complete. In src/output/picker_preview.rs, the file system watcher triggers row updates:
watcher
.watch(cache_dir, RecursiveMode::NonRecursive)
.expect("watch CI cache");
for event in watcher.rx.iter() {
if let EventKind::Modify(_) = event.kind {
// Re-render the row with fresh CI/PR data
list.render_row(updated_row);
}
}
This progressive refresh strategy updates the CI column after the network request finishes, without requiring the user to restart the command.
Network Safety Guarantees
Worktrunk implements several safeguards to handle unreliable networks gracefully.
Non-Blocking UI Architecture
The initial render cycle completes before any network request finishes. CI columns appear empty initially and populate as background fetches resolve. This guarantees that slow forge APIs cannot stall the entire wt command.
Timeout Handling
Background processes inherit a global REMOTE_DETECTION_TIMEOUT (approximately 30 seconds). Commands exceeding this threshold are terminated, preventing indefinite hangs when GitHub or GitLab experiences outages.
CLI Abstraction
By delegating network operations to the official gh and glab CLIs rather than implementing raw HTTP clients, Worktrunk leverages those tools' authentication handling, rate limiting, and retry logic automatically.
Key Source Files
Understanding the implementation requires examining these specific modules:
src/cache.rs– Implements the file-based CI-status cache read/write operationssrc/output/concurrent.rs– Runs background forge commands safely using theCmdwrappersrc/picker/prs.rs– Manages per-worktree PR fetches and picker UI coordinationsrc/utils.rs– Containswrite_atomicallyfor safe cache persistencetests/integration_tests/config_state.rs– Validates CI cache creation and state managementtests/integration_tests/switch_picker.rs– Demonstrates mocked PR JSON handling and UI refreshtests/integration_tests/ci_status.rs– End-to-end integration tests for the full CI detection pipeline
Summary
- Worktrunk uses a cache-first strategy checking
.git/wt/cache/ci-status/<branch>.jsonbefore making network requests - Network queries run via background CLI processes (
ghorglab) spawned throughCmd::new(...).run()insrc/output/concurrent.rs - All data exchanges use structured JSON (
--jsonflags) to avoid fragile text parsing - Cache writes are atomic (
write_atomicallyinsrc/utils.rs) to prevent data corruption - The UI updates via file-system events (
notifycrate) without blocking the initial render - 30-second timeouts (
REMOTE_DETECTION_TIMEOUT) prevent slow networks from hanging the interface
Frequently Asked Questions
How does Worktrunk avoid blocking the UI when checking CI status?
Worktrunk renders the initial interface immediately using cached data or empty placeholders. It spawns background processes via Cmd::new(...).run() in src/output/concurrent.rs to query gh or glab, then updates individual rows via file-system events when the cache updates. This ensures wt list remains responsive even during slow network conditions.
What happens if the GitHub CLI is not installed?
If Worktrunk cannot detect the gh binary (or glab for GitLab), it skips the CI status display entirely. The picker continues to function normally, showing worktree information without the CI/PR badges. The tool does not crash or hang when CLI tools are missing.
Where does Worktrunk store CI status cache files?
Worktrunk stores CI cache files under .git/wt/cache/ci-status/<branch>.json relative to the repository root. The src/cache.rs module handles reading these files, while src/utils.rs contains the atomic write logic that ensures cache integrity during concurrent access.
How does Worktrunk handle API rate limits or timeouts?
Background CLI processes inherit a REMOTE_DETECTION_TIMEOUT of approximately 30 seconds. Worktrunk relies on the underlying gh and glab CLIs to handle HTTP retries and rate limiting, simply terminating the subprocess if it exceeds the timeout threshold. Failed fetches result in empty CI columns rather than error messages breaking the UI.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →