Excel for the terminal. An interactive TUI spreadsheet with natural language queries.
A Really Artificial project.
Open CSV, JSON, Parquet, and Excel files in a fast TUI spreadsheet. Filter, sort, pivot, and export visually. Ask questions in plain English and let xeli write the SQL.
→ www.reallyartificial.org/work/xeli/playground/
DuckDB-WASM in your browser. Load a CSV and query it locally with SQL. Optional AI queries send your question and column schema to your chosen provider using your API key.
# npm (one-off, no install)
npx @josharsh/xeli examples/employees.csv
# npm (global)
npm install -g @josharsh/xeli
# Homebrew
brew install josharsh/tap/xeliThe npm package and Homebrew tap retain their existing names for compatibility.
Or grab a prebuilt binary.
Supported on macOS (Apple Silicon, Intel) and Linux (arm64, x86_64). Windows isn't supported yet, see #help-wanted.
xeli sales.csv # open a CSV
xeli data.parquet # or Parquet, JSON, JSONL, Excel
cat events.json | xeli # pipe anything
psql -c "..." | xeli # query results, browsable
xeli # no args opens a file picker for the current dirPress Ctrl+K and ask something:
- "top 10 employees by salary"
- "average revenue by city for active customers"
- "signups per week last quarter"
xeli sends your schema plus the question to OpenAI or Anthropic, runs the returned SQL on DuckDB, and shows the rows.
| Multi-format | CSV, TSV, JSON, JSONL, Parquet, xlsx |
| AI queries | Ctrl+K, plain English to SQL via OpenAI or Anthropic |
| SQL mode | Ctrl+Q, direct DuckDB queries with history |
| Filter | f, visual builder with 12 operators (=, >, contains, regex, ...) |
| Sort | s, cycle current column ASC / DESC / off |
| Search | /, regex across all columns, n and N to walk matches |
| Group-by + pivot | g, multi-column grouping wizard with COUNT, SUM, AVG, MIN, MAX |
| Join | J, pick a second file, choose INNER / LEFT / RIGHT / FULL |
| Computed columns | c, derive new columns from expressions (price * qty) |
| Formula bar | =, one-shot expressions (SUM(amount), MEDIAN(salary)) |
| Histograms | v, sparkline distribution for any numeric column |
| Column stats | Ctrl+I, min / max / mean / median / nulls / unique count |
| Export | e, write filtered result back out as CSV / JSON / Parquet |
| Themes | t, Dracula, Nord, Catppuccin, Tokyo Night, Solarized |
| Command palette | Ctrl+P, fuzzy-search every command |
| Undo | u, full view-state stack |
| File picker | run xeli with no args for a fuzzy list of supported files in cwd |
| Mouse | click, scroll, drag to resize columns |
Full keybinding list lives in the in-app help (?) or in src/handlers/input.rs.
They're all great. Here's how xeli finds its niche:
| Tool | Best for | What xeli does differently |
|---|---|---|
| VisiData | Mature, scriptable Python TUI | DuckDB engine plus an AI natural-language query layer |
| csvkit | Pipeline transforms | Interactive browsing instead of one-shot scripts |
| xsv | Blazing fast CSV processing | Multi-format (Parquet, JSON, xlsx) plus TUI plus SQL |
| Miller | Streaming transforms across formats | Interactive table, group-by wizard, joins by point-and-click |
| sc-im | Classic spreadsheet UX | Less Excel-cell-editing, more "browse + query large data" |
| q | SQL over CSVs from the shell | Same idea, plus a TUI, plus NL queries, plus more file formats |
If you live in a notebook for ad-hoc data exploration, xeli is the "I just want to look at this CSV without spinning up Python" tool.
xeli works without AI. Every feature except Ctrl+K runs offline. To turn natural language queries on, set an API key:
# OpenAI
export OPENAI_API_KEY=sk-...
# or: xeli config set-key openai sk-...
# Anthropic (Claude)
export ANTHROPIC_API_KEY=sk-ant-...
# or: xeli config set-key anthropic sk-ant-...If you press Ctrl+K with no key set, xeli walks you through it inline. Pick a provider, paste your key, hit Enter. No restart needed.
Sample datasets live in examples/:
xeli examples/employees.csv # 30 rows x 7 columns
xeli examples/departments.csv # join target
xeli examples/employees.json # same data, JSONTry this in the AI bar (Ctrl+K):
top 3 highest-paid people in engineeringaverage salary by department, ordered by amountwho has been here the longest in each city?
Or join two files (J):
- Open
examples/employees.csv - Press
J, enterexamples/departments.csv - Pick
INNERjoin, both on thedepartmentcolumn
cargo build --release
./target/release/xeli examples/employees.csvTests (release mode is required on macOS):
cargo test --release- Rust. Single static binary, ~3k LOC, no runtime dependencies.
- Ratatui for the terminal UI.
- DuckDB as the embedded vectorized SQL engine.
- clap for CLI parsing.
- tokio as the async runtime for the one AI request.
A short, deterministic walk-through. Open a CSV, navigate, sort by salary, then run the group-by wizard for AVG(salary) per department.
PRs welcome. See CONTRIBUTING.md for the build and test loop and the open help-wanted list (Windows, Ollama backend, streaming, themes).
MIT. See LICENSE.

