A Guake-style drop-down terminal emulator for Linux (X11), built with Rust using alacritty_terminal, gpui (Zed's GPU-accelerated UI framework), and wattaouille for power monitoring.
Terminal
- Drop-down terminal toggled with global hotkeys (default: ` and XF86Calculator, customizable in preferences)
- Full terminal emulation via alacritty_terminal (colors, scrollback, bracketed paste, ...)
- GPU-accelerated rendering via gpui
- Text selection with mouse, copy/paste from context menu
- Clickable URLs and file paths detected in terminal output
- Reset input & color for misbehaving programs
Tabs
- Multiple tabs with drag-and-drop reordering
- Double-click to rename, right-click context menu
- Ctrl+Shift+T to open a new tab (inherits working directory)
- Alt+Tab to cycle between tabs
- Shell exit detection with close/respawn confirmation
Session
- Tabs, working directories, and full terminal output persisted across restarts
- Active tab selection restored on startup
Preferences
- Theme selection (Dark, Tomorrow Night Blue)
- Window opacity (1%-100% slider)
- Language (English, French)
- Configurable toggle hotkeys (press any key to register, applied immediately)
- Configurable browser and code editor for opening links
Monitoring
- Per-tab CPU usage, power draw (watts), energy consumption (Wh), and uptime
- Low battery warning with visual indicator
Integration
- HTTP API with token auth and QR code for remote tab management from a phone
- Wakatime time tracking (reads API key from Zed settings)
- Screenshots (per-tab or full app) saved as BMP
cargo build --release
# Binary at target/release/tab-atelierRequires Rust 2024 edition (rustc 1.92+).
cargo deb
sudo apt install ./target/debian/tab-atelier_*.debThe .deb lays out the following under FHS-standard paths:
| Path | Permission | Contents |
|---|---|---|
/usr/bin/tab-atelier |
0755 |
The binary |
/usr/share/applications/tab-atelier.desktop |
0644 |
Desktop entry (registers Tab Atelier in app launchers) |
/usr/share/icons/hicolor/scalable/apps/tab-atelier.svg |
0644 |
App icon (scalable SVG, picked up by the desktop environment via the Icon=tab-atelier line in the .desktop) |
/usr/share/doc/tab-atelier/ |
0644 |
README.md, LICENSE, copyright |
conffiles (per debian-policy §10.7.2): none. tab-atelier ships no system-wide configuration in /etc, so dpkg has no files to track between upgrades. All user-modifiable state — preferences, tab list, scrollback, uptime, energy, single-instance lock — lives under the user's $XDG_CONFIG_HOME and $XDG_STATE_HOME (see State below). The package's conf-files = [] in Cargo.toml records this intentionally.
dirs (per debian-policy §10.5): the package creates only what it installs (under /usr/bin, /usr/share/applications, /usr/share/icons/hicolor/scalable/apps, /usr/share/doc/tab-atelier). It does not pre-create any directory under /etc or /var. The per-user ~/.config/tab-atelier/ and ~/.local/{,state/}tab-atelier/ directories are created lazily by the running application on first save — dpkg never touches them, so a dpkg --purge leaves them in place for the user to remove manually if desired.
tab-atelier # normal mode
tab-atelier --read-only # second instance, no writesA normal launch acquires a single-instance lock on ~/.local/state/tab-atelier/tab-atelier.lock and exits if another normal instance is already running — concurrent writers would race each other and produce inconsistent state files.
--read-only skips the lock so any number of read-only instances can run alongside the primary one. In that mode tab-atelier never writes anything: no tabs.json rewrites, no per-tab output / uptime / energy files, no preference saves, no rename-time file moves. The preferences "Save" button is visually disabled. Useful for snapshotting the running workspace from a script or for poking around without disturbing live state.
Tab Atelier reads font configuration from your Zed editor settings:
File: $XDG_CONFIG_HOME/zed/settings.json (defaults to ~/.config/zed/settings.json)
| Setting | Description | Default |
|---|---|---|
ui_font_family |
Terminal font family | monospace |
ui_font_weight |
Font weight (100-900) | 400 |
ui_font_size |
Font size in pixels | 16 |
buffer_font_size |
Fallback if no ui_font_size | 16 |
scroll_sensitivity |
Scroll speed multiplier | 1.0 |
In-app preferences (theme, opacity, language, browser, code editor) are stored in:
File: $XDG_CONFIG_HOME/tab-atelier/preferences.json (defaults to ~/.config/tab-atelier/preferences.json)
Tab Atelier splits persisted state across four files to keep a bad write to any one piece from corrupting the rest. Each file is written atomically (.tmp + fsync + rename) with rotated backups (.bak, .bak.1, .bak.2).
| Data | Path | Notes |
|---|---|---|
| Tab list, working directories, active index | ~/.local/tab-atelier/tabs.json |
Tiny, rewritten on every persist tick (~2 s) |
| Per-tab terminal scrollback | ~/.local/state/tab-atelier/output_tab-<sanitized>-<crc32>.json |
One file per tab. Rewritten on every persist tick |
| Per-tab uptime (active seconds) | ~/.local/state/tab-atelier/uptime_tab-<sanitized>-<crc32>.json |
One file per tab. Throttled to once every 30 s; final value flushed on shutdown |
| Per-tab energy (Wh) | ~/.local/state/tab-atelier/power_tab-<sanitized>-<crc32>.json |
One file per tab. Throttled by delta (≥ 0.1 Wh consumed); final value flushed on shutdown |
| Single-instance lock | ~/.local/state/tab-atelier/tab-atelier.lock |
Empty file. Held via flock(2); released automatically by the kernel on process exit (including crashes), so no manual cleanup needed |
Tab filename = sanitized tab name (non-[A-Za-z0-9._-] → _) plus an 8-hex-digit CRC32 of the original name, so two tabs whose sanitized forms collide (e.g. foo/bar and foo_bar) still land in distinct files. Renaming a tab in the UI moves all four files (output, uptime, power, plus their .baks) to the new name's slot so history isn't orphaned.
On Intel systems with readable RAPL counters, each tab shows its estimated power usage in the right-click context menu. The estimate uses the same technique as wattaouille: per-tab watts = package watts * (tab CPU jiffies / total system jiffies). When RAPL is not available, only CPU percentage is shown.
Since CVE-2020-8694 (PLATYPUS side-channel) the kernel ships /sys/class/powercap/intel-rapl/intel-rapl:*/energy_uj as mode 400, owned by root, so a regular user — including the one running tab-atelier — gets Permission denied. Symptom: the watts column on every tab card is empty, the stats popover shows CPU% only, and ~/.local/state/tab-atelier/power_tab-*.json files never get created.
One-shot for the current boot:
sudo chmod -R g+r,o+r /sys/devices/virtual/powercap/intel-raplPersistent (every boot) — drop a udev rule:
echo 'SUBSYSTEM=="powercap", ACTION=="add", RUN+="/bin/chmod -R g+r,o+r /sys/devices/virtual/powercap/intel-rapl"' | sudo tee /etc/udev/rules.d/99-rapl.rules
sudo udevadm control --reload
sudo udevadm trigger --subsystem-match=powercapAfter either, restart tab-atelier. PowerSensor::detect runs once at startup, so a mid-session permission fix is only picked up by the next launch.
What are jiffies? Jiffies are the Linux kernel's internal time-keeping unit — a counter that increments at a fixed rate (typically 100, 250, or 1000 Hz depending on CONFIG_HZ). Each tick, the kernel records CPU time consumed by every process. Per-process jiffies are read from /proc/[pid]/stat and total system jiffies from /proc/stat. The ratio between them gives the fraction of CPU a tab's shell used, which is multiplied by package power (from Intel RAPL) to estimate per-tab wattage.
Tab Atelier exposes tab state on http://<local-ip>:7890 as JSON. Access requires a bearer token, shown via a QR code in the right-click menu ("Remote control"). The response includes tab names, working directories, active tab index, and per-tab power stats. Tabs can be closed remotely via DELETE /tabs/{index}.
Wakatime integration is automatic if your Zed settings contain wakatime.settings.api-key. Heartbeats are sent with project detection (walks up to find .git).
Control log output with the RUST_LOG environment variable:
RUST_LOG=tab_atelier=info cargo run # Startup, restore, API
RUST_LOG=tab_atelier=debug cargo run # Verbosecargo test
cargo clippyMPL-2.0
Terminal rendering patterns based on Zed (Apache-2.0 / GPL-3.0).

