MARS
Mission control for your terminal — a non-modal, Emacs-compatible terminal editor with a Claude-Code-style mission-control command bar, a built-in LLM agent, real terminal panes, and tmux/zellij-style persistent sessions. One tool, one set of keys.
███╗ ███╗ █████╗ ██████╗ ███████╗
████╗ ████║██╔══██╗██╔══██╗██╔════╝
██╔████╔██║███████║██████╔╝███████╗
██║╚██╔╝██║██╔══██║██╔══██╗╚════██║
██║ ╚═╝ ██║██║ ██║██║ ██║███████║
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
Build & install
# put it on your PATH:
Quick start
Sessions are the default, tmux-style: a bare mars gets an auto-numbered session
that survives closing the window. Press any key to dismiss the startup banner.
Inside the editor, four keys carry you everywhere:
| Key | What it does |
|---|---|
Ctrl+Space |
mission control — search every command (type to filter, Enter to run); works in terminal panes too |
! (in mission control) |
run a shell command in a terminal pane |
? (in mission control) |
ask the built-in agent anything ("how do I split the screen?") |
C-x C-f |
Navigator — browse & jump to any project file (type to fuzzy-filter) |
C-t |
space warp: tabs, panes, splits — with an on-screen cheat panel |
C-g cancels anything. Every menu row shows its real keybinding, so the fast path
teaches itself as you go.
Moving around fast
Fast motion is bound to ⌥ (Option) and to C-x jumps that work on every
terminal (enable "Use Option as Meta" if your terminal offers it).
| Do this | Keys | Also |
|---|---|---|
Jump by code token (foo·.·bar·(·baz·)) |
⌥← / ⌥→ |
M-b / M-f (word) |
| Page up / down | ⌥↑ / ⌥↓ |
PageUp / PageDown |
| Extend selection while jumping | add Shift (⌥⇧→) |
Shift+PageUp/Down |
| Next/prev blank-line block | C-x ] / C-x [ |
|
Next/prev definition (fn/def/class…) |
C-x } / C-x { |
|
Matching bracket ()[]{} |
C-x m |
Search doubles as teleport. C-s, type a word you can see — it jumps as you
type, with a 3/12 counter. Press Tab and every visible match gets a one-letter
label; press a label to teleport straight there. And you don't have to press Enter:
just start editing or hit a motion key — the search commits at the current match and
your key applies. C-s/C-r cycle matches, C-g cancels (restoring where you
started).
Sessions — replace tmux/zellij
Sessions keep your buffers, panes, and running shells alive when the window closes, the SSH connection drops, or you just walk away.
The daily rhythm:
- Start:
marsormars new work— everything from here on lives in the daemon. - Detach when you want the terminal back: press
C-tthenD— or just close the window. Both leave shells running and buffers intact. - Come back:
mars attach(ormars attach work). Your layout, buffers, and that build you left running in a terminal pane are exactly where you left them. If anything happened while you were gone, the Mission Briefing boots up like a console coming online — a mission clock, a plain-English situation report in the mission-control voice that types itself in ("The trainer went down at epoch 3 — CUDA OOM, needs a smaller batch. The build came home green."), then a systems board of every workstream (failures first, then blocked ⏸, done ✓, running) with a "why" line under anything that failed and a teal ★ on a long run that finished clean. Any key resumes exactly where you left off. Each briefing is remembered, so the next return reports progress against it. Nothing happened → no briefing. (mission_briefing = 1swaps it for a one-line notice;C-x gstill opens the full Away Digest timeline anytime.) - Finish for real: quitting (
C-x C-c) just detaches — a session only ends when you kill it: Kill session in the command bar (confirm-gated),mars kill workfrom outside, ormars killallto sweep every session and start fresh.
mars ls tells you the state at a glance:
SESSION STATUS
work detached — reattach: mars attach work
review attached
Safety nets, on by default: modified files autosave every 30s and on every
detach/disconnect (scratch buffers are never touched), and each daemon logs to
~/.local/state/mars/<name>.log — if a session ever dies, the postmortem is there.
Notes: one client per session — attaching from a second window takes over from the first (it gets a clean "another client attached" message). Attaching from a different-sized terminal just reflows.
The agent
Beta. The AI features — the
?ask flow, agent-proposedRUN:/TYPE:directives, refactors, triage, watch summaries, and the away digest — are new and still being tuned. Treat the agent as an assistant, not an authority: review what it proposes before running it (destructive actions are gated, but read them). The core editor, multiplexer, and sessions are stable.
Works out of the box with a free-tier key from any of:
# Claude — defaults to claude-haiku-4-5
# OpenAI — defaults to gpt-4o-mini
# Groq (free tier) — defaults to qwen/qwen3-32b
# Google AI Studio (free tier) — gemini-3.1-flash-lite
# or any OpenAI-compatible endpoint (e.g. local Ollama):
# override the model for any provider:
Detection is paid-first: if several keys are set, Claude → OpenAI → Groq → Gemini
(an explicit MARS_LLM_KEY always wins). Cheap defaults per provider — reach for a
bigger model with MARS_LLM_MODEL, not by default.
Calibrating cost/latency (debug mode). To see where tokens and time actually go —
so you can right-size the model per task — run with --llm-debug (or MARS_LLM_DEBUG=1)
to log every call, then profile it:
# TASK MODEL N AVG_IN AVG_OUT TOT_TOK %TOK AVG_MS ERR
# watch qwen/qwen3-32b 2 6050 195 12490 62% 3025 0 ← heaviest
# ask qwen/qwen3-32b 2 1720 215 3870 19% 900 0
Reasoning models (Qwen3, DeepSeek-R1) work — their <think> blocks are stripped from
answers automatically.
Then ? in mission control, or from the shell:
The agent works on every box — your key never leaves home
Beta. The SSH features (
mars ssh,mars keyd, the fleet view, and the remote installer) are new and still being hardened — as are the AI features they carry (see The agent). The core editor, multiplexer, and sessions are stable; the remote/tunnel path may have rough edges — please report anything you hit.
You set your key once, on your own machine, and the agent works on every host you SSH into — without the key ever landing on a remote box (not in its env, not in its shell history, not on its disk).
# key broker if needed (inheriting this shell's API key).
# `mars` on gpubox → the agent just works. No key on the box.
(The broker — mars keyd — starts on demand the first time you mars ssh; run it
explicitly only if you want it in a specific shell.)
Installing mars on a fresh host. Mars needs a modern Rust toolchain (≥ 1.85) — a
distro-packaged cargo (e.g. Ubuntu's 1.75) is too old and fails with a cryptic
edition2024 error. Don't apt install cargo; install rustup (the official way,
from rust-lang.org/tools/install), then
install mars from crates.io:
|
(install.sh in this repo automates exactly those steps, including detecting a
too-old distro cargo.) Your API key never lands on the box — it's served from home
over the tunnel.
The remote never makes the LLM call itself — it proxies the request home through the
SSH tunnel, and the completion comes back. Compromise the box and there's nothing to
steal; close your laptop and remote access ends with the tunnel. Jump hosts,
ProxyCommand, and hardware keys all work (it wraps your real ssh). mars ls shows
the hosts you've been on, newest first — type a number or a name to hop back.
The agent sees your screen — editor buffers, terminal output, your layout — so
"why did this build fail?" needs no copy-paste. It holds a conversation (C-l
starts a fresh one), and it can act: RUN: fires an editor action, TYPE: types
a shell command into your terminal pane, OPEN: jumps to a path:line from a stack
trace — always shown first, always one explicit Enter away, never automatic.
What that unlocks:
- Ask about a selection. Select code (
Shift+arrows orC-x h), then?— the exact selection goes along as context, not just the visible screen. - Reversible refactors. Ask "simplify this" / "add error handling" on a
selection: the panel shows
▶ Enter to replace the selection (N lines). Enter applies it as one undo step, so a singleC-/reverts the whole AI edit. - Triage.
C-x ?(or "why did this fail?" in the bar) grounds the agent in the focused terminal's output;C-x eexplains what's at the cursor. - Watch a pane. Kick off a long command, then
C-t w. When it exits or goes quiet (~20s), Mars leaves a one-line verdict at the bottom, failures first (✗ failed: linker error · build).Escdismisses. This fires even while detached — the daemon keeps watching, somars attachlater lands on the verdict. - Ask beyond the visible screen. Questions like "when did this first start failing?" or "does the error in the api tab match this code?" let the model request more context (the pane's full scrollback, or another tab); Mars supplies it and re-asks once, silently. You do nothing special.
- Shell translation. In a terminal pane,
Ctrl+Spacethen plain English ("find big files here") → the agent translates it to a shell command and shows it for you to confirm. Typed a real Mars command instead? It's recognized and run directly. (!still forces shell,?asks,@opens Navigator.)
With an agent connected, tabs you haven't named get a quiet auto-generated label
from their content (rename one yourself and it's yours forever; auto_name_secs = 0
turns it off).
Keys you already know
Mars speaks three dialects at once — whichever your fingers know:
- Navigator (browse files):
C-x C-f— orCtrl+Spacethen@— opens Navigator, the file sidebar on the left. Folders are bold + colored and collapsed — arrow to one andEnter/→expands it in place (←collapses); on a file,→previews it (reversible) andEnteropens it;../at the top steps up a directory. Start typing to fuzzy-filter the whole project to a shortlist;Esccloses. - Emacs:
C-x C-ssave ·C-x C-fopen ·C-sisearch ·M-%query-replace (y/nstep,!all) ·C-k/C-ykill/yank ·C-x 2/C-x 3/C-x owindows ·M-xmission control - Modern/Mac:
C-c/C-vcopy/paste (system clipboard) · Shift+arrows select · typing replaces selection ·Tab/Shift-Tabindent/dedent a selected block · mouse click/scroll/wheel - tmux/zellij:
C-tspace warp ·M-{/M-}orC-PgUp/PgDnswitch tabs ·M-1..9jump to tab ·C-o/Ctrl+arrowsmove between panes ·C-|/C--splits · scrollback with the wheel orShift+PgUp/PgDn
Undo, two ways. C-x u (or C-/) undoes — a typed run coalesces into one step, and
an applied AI refactor is always exactly one step. M-/ redoes. For bigger jumps, C-u
opens time-travel: ←/→ scrub back and forward through your edit history, Home
rewinds to the very start, End returns to now, Esc done.
Everything is remappable in ~/.config/mars/keys.json; behavior knobs (autosave
interval, scrollback depth, colors, timings, watch quiet threshold) live in
~/.config/mars/tuning.json, each with a plain-English description of what it does.
Broke your config experimenting? mars reset restores default keys + tuning (your
old files are kept as *.bak).
Troubleshooting
- Staircase output (lines drifting right, like
mars helpprinting diagonally): your shell's terminal was left in raw mode — usually by a force-killed program. Run anymarscommand (it repairs the terminal automatically on startup) orstty sane. M-…keys do nothing (macOS): enable "Use Option as Meta" in Terminal/iTerm — or use theCtrl-based twins (C-o,Ctrl+arrows), which always work.- A session shows
dead (cleaned up)inmars ls: the daemon crashed or the machine rebooted. Check~/.local/state/mars/<name>.logfor the reason; autosaved file changes are already on disk. - Fancy chords (
C-{,C--) don't fire: they need a kitty-protocol terminal. The Alt-based twins work everywhere.
More
architecture_overview.md— a file-by-file tour of the code: what lives where and how the pieces connect.DESIGN.md— architecture rationale, tradeoffs, and how the pieces fit.key_design.md— the design doctrine and product vision (why the keys are what they are, and where Mars is going).AGENTS.md— instructions for AI coding agents working on Mars.