Argus: Small software, deliberately
Argus is a TUI-based unified control plane for agent sandboxing written in Rust, but this post isn't about agents or sandboxing. It's about what happens when every dependency, every default, and every line has to earn its place.
For the people who build CLI/TUI dev tools, and for anyone who just likes seeing how small software stays small.
In Motion
The whole lifecycle (start, draw, keypress, shutdown) fits in less than half a human blink.
Why this matters
Argus is a TUI-based unified control plane for agent sandboxing written in Rust. But this post isn't about agents or sandboxing. It's about what happens when every dependency, every default, and every line of code has to earn its place.
If you build CLI/TUI dev tools, or you just like seeing how small software stays small, this is for you.
Most modern dev tools accrete weight by accident. A logging framework here, an async runtime there, an argument parser, a config loader, three serialization formats. One day you ship a 50 MB binary that takes 400 ms to draw its first frame and spins your fan at idle.
Argus picks the other path. Each “no” is deliberate. Each megabyte saved is a vote for the user's laptop battery, their patience, and their trust.
“Small tools punch above their weight when every NO is deliberate.”
The Benchmarks
Measured, not estimated. Numbers that match what your eye sees.
Binary Size, in Context
The tools you trust on your $PATH every day. And Argus.
Argus is ~10× smaller than gh and ~36× smaller than k9s.
How It Stays Small
One foreground thread. One background worker. A channel between them. That's the entire concurrency model.
Render on change
Polls the keyboard with a 50 ms timeout. Only calls terminal.draw() when input arrives, the terminal resizes, or the worker reports state actually changed. No 60 Hz loop. No wasted frames.
Just a channel
The standard library's own channel. No tokio. No crossbeam. No async ceremony. Jobs flow one way, results flow back.
All the slow stuff
HTTP calls, polling for IPs, SSH probes, long-running provision steps. It blocks freely, but only itself. The UI never waits on it.
No shared state. No locks. No data races. The mpsc-worker pattern is a Pareto-optimal point that almost no Rust tutorial teaches, and it gives you everything an async runtime gives you for a fraction of the cost.
Every “No” Was Deliberate
Each dependency had to pass a single test: do I really need this? Most didn't.
No async runtime
Tokio adds megabytes and a colored-function tax. The whole app fits in one foreground thread plus one worker.
No CLI parser
There are no flags. Argus has one job and runs it. clap is half a megabyte you don't owe anyone.
No logging framework
Errors bubble up with anyhow context. Live logs stream to the UI. tracing/log are not in the build graph.
No async HTTP
ureq is a few hundred KB of pure sync. reqwest pulls in tokio, hyper, h2, rustls, and you'd never notice the cost until you wonder why your binary is 30 MB.
No 60 Hz redraw loop
Most TUIs repaint 60 times a second whether anything changed or not. Argus paints when something actually moved. That's why idle CPU rounds to zero.
No shared state
The UI thread and the worker thread never touch the same memory. They communicate by passing messages on a channel. No locks. No data races. No bugs of that shape.
Building a CLI or TUI?
The discipline that built Argus is the same discipline that builds developer tools people actually keep installed. Let's talk about yours.