DEV Community

Cover image for I Built a Desktop App That Starts My Entire Dev Environment With One Click (Using Tauri + Rust + React)
TROJAN
TROJAN

Posted on

I Built a Desktop App That Starts My Entire Dev Environment With One Click (Using Tauri + Rust + React)

Every morning I would open 4 terminal tabs, cd into different folders, and run some combination of npm run dev and cargo run. Then I'd forget which terminal crashed. Then I'd do it again.

So I built Chronicle to kill that habit.

What Is Chronicle?

Chronicle is a desktop app (built with Tauri) that does two things:

  1. One-click workspace launcher — press a button, fire up all your dev servers simultaneously, watch their output stream into a tabbed terminal dashboard in real-time
  2. Git history explorer — visualize your commit graph, click commits to read diffs, and use an AI (Gemini) to summarize what changed

The Stack

Layer Technology
App Shell Tauri v2
Frontend React 19 + Vite 7 + TypeScript
Backend Rust (async, via Tokio)
Styling Tailwind CSS v4
Animations Framer Motion
AI Google Gemini

Why Tauri?

Tauri lets you write your UI in whatever web framework you want, then wraps it in a native OS window using Rust. The result is a .exe that's tiny, fast, and has full access to the OS. No Electron 300MB bloat. No compromises.

The Rust backend part is what made the launcher feature possible. Here's the core of how it works:

#[tauri::command]
async fn start_all_processes(
  app: AppHandle,
  state: tauri::State<'_, Arc<AppState>>,
  project_path: String
) -> Result<(), String> {
  // Spawn each process asynchronously
  spawn_and_stream(app.clone(), state.clone(), "buildforge", 
    "npm", &["run", "dev"], &format!("{}\\BuildForge", project_path)).await?;

  spawn_and_stream(app.clone(), state.clone(), "airwebreathe", 
    "npm", &["run", "dev"], &format!("{}\\AirWeBreathe", project_path)).await?;

  Ok(())
}
Enter fullscreen mode Exit fullscreen mode

The spawn_and_stream function uses Tokio to spawn processes async, reads their stdout/stderr line by line, and emits each line to the React frontend using Tauri's event system.

On the React side, listening for those events looks like:

const unlistenOutput = await listen<LogPayload>('process-output', (event) => {
  setLogs(prev => ({
    ...prev,
    [event.payload.id]: [...(prev[event.payload.id] || []), event.payload.line]
  }));
});
Enter fullscreen mode Exit fullscreen mode

That's it. Real-time streaming terminal output from Rust to React in so few lines.

The UI

The whole thing is themed after GitHub dark mode (#0d1117, subtle borders, green accents). The launcher screen has one big green button. The dashboard that opens shows tabbed terminal output for each running process, auto-scrolling, color-coded (green = success, red = error).

What I Learned

1. Tauri is genuinely underrated. The developer experience is excellent, the apps are fast, and the security model is much more sensible than Electron.

2. Tokio makes async process spawning a joy. tokio::process::Command + BufReader + lines() is all you need to stream terminal output.

3. Tauri's event system is a perfect bridge. app.emit("event-name", payload) from Rust, listen("event-name", handler) from TypeScript. Clean and simple.

Try It

git clone https://github.com/TROJANmocX/Chronicle.git
npm install
npm run tauri dev
Enter fullscreen mode Exit fullscreen mode

If you're building dev tooling or have ever thought "I should automate my terminal workflow" — Tauri + Rust is a genuinely great choice. Feel free to drop questions in the comments.

Happy building! 🗡️

Top comments (0)