npm install -g dotdotdot-cli
You know what you want. You just don't know the command.
... takes plain English and gives you the exact terminal command for your OS, your shell, your setup. Execute it, copy it, or just look at it. Nothing runs without your say-so.
Quick mode — say it, get it
... show my public IP
... find all files over 100MB
... undo my last git commit
... what's eating my RAMTask mode — chain steps together
... find all .tmp files then delete them
... check node version, scaffold a new app
... build the project then deploy to staging
... ping popular DNS and show the fastestnpm install -g dotdotdot-cli
... -c # add your API key (you need at least one)
... show my disk usageOr use environment variables
export DOT_OPENROUTER_KEY=sk-or-...
export DOT_ANTHROPIC_KEY=sk-ant-...
export DOT_OPENAI_KEY=sk-...
export DOT_GOOGLE_KEY=AIza...
export DOT_CUSTOM_KEY=sk-...- How It Works
- Quick Mode
- Task Mode
- Examples
- Context Awareness
- Session Memory
- Safety
- Providers
- Token Tracking & Cost
- Flags
- Config
- Shell Aliases
- Why
... - Project Structure
you type something in plain english
↓
... gathers context ─── OS, shell, cwd, git, tools, project info
↓
sends it to your chosen LLM
↓
you get back a command (or a multi-step plan)
↓
you decide: execute ─ copy ─ skip
You always choose. ... never runs anything behind your back.
One request. One command. The right one.
... compress this folder into a zip
... show running docker containers
... make a new react project called my-app
... list all open ports
... what version of python do I haveYou pick what happens:
| Key | Action |
|---|---|
| e | Execute the command |
| c | Copy to clipboard |
| i | Insert (print to stdout) |
| q | Cancel |
Chain actions with -t, or just use natural words like "then", "and", or commas.
... breaks it into steps, shows you the full plan, and runs them one at a time.
... find all .tmp files then delete them
... read my desktop files and propose a new organization
... locate project my-site, install deps, then start dev serverBefore anything executes, you see everything. You can:
- Run all at once
- Go step by step
- Skip or abort any step
- Retry if something fails
Dangerous steps always pause and ask first.
Real terminal sessions. Debug mode (-d) shows timing, provider, and token cost.
| List files in the current directory |
Session
$ ... -d list files
✔ ctx 688ms | openrouter/google/gemma-4-31b-it | mode: quick
✔ done
❯ Get-ChildItem -Path .
Lists all files and directories in the current working directory.
✔ Execute
Directory: C:\Users\you\Projects\my-app
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 4/4/2026 4:22 PM src
d----- 4/4/2026 4:22 PM node_modules
-a---- 4/4/2026 3:17 PM 1157 package.json
-a---- 4/4/2026 5:38 PM 14098 README.md
tokens: 711 in 43 out (754 total) ~$0.000117
✔ exit 0
| What's my public IP address? |
Session
$ ... -d what is my public ip address
✔ ctx 209ms | openrouter/google/gemma-4-31b-it | mode: quick
✔ done
❯ (Invoke-RestMethod -Uri 'https://api.ipify.org').Trim()
Uses Invoke-RestMethod to query the ipify API and retrieve the public IP address.
✔ Execute
203.0.113.42
tokens: 715 in 57 out (772 total) ~$0.000123
✔ exit 0
| Show disk usage |
Session
$ ... -d show me the disk usage
✔ ctx 211ms | openrouter/google/gemma-4-31b-it | mode: quick
✔ done
❯ Get-PSDrive C | Select-Object Name, @{Name='Used(GB)';Expression={...}}, ...
Retrieves disk usage statistics for the C drive, converting bytes to
gigabytes and rounding to two decimal places.
✔ Execute
Name Used(GB) Free(GB) Total(GB)
---- -------- -------- ---------
C 256.36 218.36 474.72
tokens: 714 in 135 out (849 total) ~$0.000154
✔ exit 0
| Find the fastest DNS provider |
Session
$ ... -d -t find the best dns provider by pinging popular ones and show me the fastest
✔ ctx 213ms | openrouter/google/gemma-4-31b-it | mode: task
✔ 1 steps planned | tokens: 837 in 256 out (1.1k total) ~$0.000220
Pings Google, Cloudflare, OpenDNS, and Quad9 to determine the fastest DNS provider.
─ 1. Ping DNS providers and sort by response time
$ $dns = @{ 'Google'='8.8.8.8'; 'Cloudflare'='1.1.1.1'; 'OpenDNS'=...
✔ Run
▶ 1/1 Ping DNS providers and sort by response time
$ $dns = @{ 'Google'='8.8.8.8'; 'Cloudflare'='1.1.1.1'; 'OpenDNS'='208.67.222.222'; ...
Provider IP AvgResponse
-------- -- -----------
Cloudflare 1.1.1.1 20
Quad9 9.9.9.9 35.5
OpenDNS 208.67.222.222 47.5
Google 8.8.8.8 80.5
✔ exit 0
✔ 1/1 done
| Check Node version, then scaffold a new project |
Session
$ ... -d check my node version, then create a new folder called test-app and initialize a new npm project in it
✔ ctx 214ms | openrouter/google/gemma-4-31b-it | mode: task
✔ 2 steps planned | tokens: 844 in 173 out (1.0k total) ~$0.000187
Checks the Node.js version and initializes a new npm project in 'test-app'.
─ 1. Check Node.js version
$ node -v
─ 2. Create folder and initialize npm project
$ New-Item -ItemType Directory -Name 'test-app'; Set-Location -Path 'test-app'; npm init -y
✔ Run
▶ 1/2 Check Node.js version
$ node -v
v22.0.0
✔ exit 0
▶ 2/2 Create folder and initialize npm project
$ New-Item -ItemType Directory -Name 'test-app'; Set-Location -Path 'test-app'; npm init -y
Wrote to C:\Users\you\Projects\test-app\package.json:
{
"name": "test-app",
"version": "1.0.0",
...
}
✔ exit 0
✔ 2/2 done
| System diagnostics with Claude — top CPU and memory hogs |
Session
$ ... -d -p claude show me the top 5 processes using the most CPU, then show the top 5 using the most memory
✔ ctx 209ms | anthropic/claude-haiku-4-5 | mode: task
✔ 2 steps planned | tokens: 869 in 287 out (1.2k total) ~$0.002304
Display top 5 CPU-consuming and top 5 memory-consuming processes.
─ 1. Get top 5 processes by CPU usage
$ Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 5 ...
─ 2. Get top 5 processes by memory usage
$ Get-Process | Sort-Object -Property WorkingSet -Descending | Select-Object -First 5 ...
✔ Run
▶ 1/2 Get top 5 processes by CPU usage
$ Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 5 ...
Name CPU MemoryMB
---- --- --------
Code 2519.78125 1118.19
Code 1688.984375 191.6
RemotePCViewerUI 1034.375 54.03
Code 582.546875 333.34
Cursor 559.28125 435.31
✔ exit 0
▶ 2/2 Get top 5 processes by memory usage
$ Get-Process | Sort-Object -Property WorkingSet -Descending | Select-Object -First 5 ...
Name MemoryMB CPU
---- -------- ---
Memory Compression 1654.66
Code 1117.14 2520.31
kilo 697.46 241.05
chrome 629.8 339.38
Cursor 435.32 559.28
✔ exit 0
✔ 2/2 done
| Git branch cleanup — find merged branches and delete stale ones |
Session
$ ... -d -p claude find all merged git branches, show them, then delete the stale ones
✔ ctx 48ms | anthropic/claude-haiku-4-5 | mode: task
✔ 3 steps planned | tokens: 853 in 397 out (1.3k total) ~$0.002838
Identify merged branches, list them with last commit info, then clean up.
─ 1. List all branches merged into main with last commit date
$ git for-each-ref --merged=main --format='%(refname:short) %(committerdate:short) ...
─ 2. Count how many stale branches will be removed
$ git branch --merged main | Select-String -NotMatch -Pattern '^\s*[*+]|^\s*(main|master)$' ...
! 3. Delete all merged branches except main/master
$ git branch --merged main | Select-String -NotMatch -Pattern '^\s*[*+]|^\s*(main|master)$' ...
✔ Run
▶ 1/3 List all branches merged into main with last commit date
$ git for-each-ref --merged=main --format='%(refname:short) %(committerdate:short) %(subject)' refs/heads/
feature/dark-mode 2024-08-12 feat: add dark mode toggle
fix/login-redirect 2024-11-03 fix: redirect loop on expired session
chore/deps-update 2025-01-19 chore: bump dependencies
feature/user-export 2025-03-28 feat: csv export for user data
▶ 2/3 Count how many stale branches will be removed
$ git branch --merged main | Select-String -NotMatch ... | Measure-Object
4
▶ 3/3 Delete all merged branches except main/master
$ git branch --merged main | Select-String -NotMatch ... | ForEach-Object { git branch -d $_.Trim() }
Deleted branch feature/dark-mode (was a3f291c).
Deleted branch fix/login-redirect (was 88d0e4f).
Deleted branch chore/deps-update (was c41b7a2).
Deleted branch feature/user-export (was 1f9d3bb).
✔ 3/3 done
| Check system uptime, then show free memory |
Session
$ ... -d show system uptime, then show free memory in GB
✔ ctx 208ms | openrouter/google/gemma-4-31b-it | mode: task
✔ 2 steps planned | tokens: 836 in 173 out (1.0k total) ~$0.000186
Retrieves system uptime and free physical memory in GB.
─ 1. Get system uptime
$ (Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
─ 2. Get free memory in GB
$ (Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB
✔ Run
▶ 1/2 Get system uptime
$ (Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
Days : 0
Hours : 15
Minutes : 36
Seconds : 23
✔ exit 0
▶ 2/2 Get free memory in GB
$ (Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB
3.65
✔ exit 0
✔ 2/2 done
... isn't guessing. It knows where it's running.
| What it detects | |
|---|---|
| OS | Windows, macOS, Linux — auto-detected |
| Shell | PowerShell, CMD, Bash, Zsh, Fish |
| Tools | node, npm, python, git, docker, etc. |
| Project | package.json, Cargo.toml, pyproject.toml |
| Git | Branch, dirty status, remote |
| Environment | WSL, Docker, SSH, virtualenv |
| History | What you just ran (session memory) |
It won't suggest brew on Windows or apt on macOS. It adapts to you.
Follow-ups just work.
$ ... find all log files
❯ Get-ChildItem -Recurse -Filter *.log
$ ... now delete them
❯ Get-ChildItem -Recurse -Filter *.log | Remove-Item
$ ... actually undo that
❯ well...
Every command is checked for risk before it touches anything.
| Risk | What happens | |
|---|---|---|
| low | Read-only, harmless | Runs freely (auto-exec if enabled) |
| medium | Creates or modifies files | Runs with your OK |
| high | Destructive (rm -rf, sudo, dd, etc.) |
Blocked in auto-mode. Always asks. |
Pick your LLM. Five providers out of the box. Switch on the fly with -p.
... -p claude explain this error
... -p gpt list my largest files
... -p gemini what does this cron do| Provider | Default Model | Flag |
|---|---|---|
| OpenRouter | gemma-4-26b-a4b-it |
-p router |
| Anthropic | claude-haiku-4-5 |
-p claude |
| OpenAI | gpt-4o-mini |
-p gpt |
| Google Gemini | gemini-2.0-flash |
-p gemini |
| Custom | (you set it) | -p custom |
Custom works with any OpenAI-compatible API — LM Studio, Ollama, vLLM, Together, etc.
Change models anytime: ... -c
Every request shows token count and cost inline:
tokens: 1.3k in 93 out (1.4k total) ~$0.000203
Check cumulative usage with ... -u:
● ● ● dotdotdot
Totals
────────────────────────────────────────────
Requests 9
Input 12.3k tokens
Output 763 tokens
Combined 13.1k tokens
Cost $0.001696
Per Request
────────────────────────────────────────────
Input 1.4k
Output 85
Combined 1.5k
Cost $0.000188
Recent
────────────────────────────────────────────
04/04 18:32 1.1k tokens $0.000220 gemma-4-31b-it
04/04 18:35 1.0k tokens $0.000187 gemma-4-31b-it
04/04 18:41 1.2k tokens $0.002304 claude-haiku-4-5
tracking since 4/1/2026
❯ Exit q
Reset usage r
Reset from the menu, or directly: ... --reset-usage
Custom pricing
... ships with pricing for all default models. For custom models, set pricing during ... -c:
❯ Price $/1M input enter to skip (current: 0.10):
❯ Price $/1M output enter to skip (current: 0.10):
Custom pricing overrides built-in defaults.
| Flag | What it does |
|---|---|
-t --task |
Force task mode |
-p --provider <name> |
Switch provider for this request |
-u --usage |
Token usage and cost stats |
-c --config |
View and edit config |
-d --debug |
Timing, provider info, debug log path |
-v --version |
Print version |
-h --help |
Help |
--clear |
Clear session history (fresh start, keeps OS/shell context) |
--reset-usage |
Clear all token tracking data |
Everything lives in ~/.dotdotdot/config.json:
... -c # view config, then exit or edit{
"provider": "openrouter",
"autoExec": false,
"providers": {
"openrouter": { "apiKey": "sk-or-...", "model": "google/gemma-4-26b-a4b-it" },
"anthropic": { "apiKey": "sk-ant-...", "model": "claude-haiku-4-5-20251001" },
"custom": { "apiKey": "sk-...", "model": "my-model", "apiUrl": "https://..." }
},
"pricing": {
"my-model": { "input": 1.00, "output": 3.00 }
}
}... works as a command in most shells. If yours doesn't like it, use dotdotdot instead:
PowerShell
# Add to $PROFILE
function ... { dotdotdot @args }Bash / Zsh
# Add to ~/.bashrc or ~/.zshrc
alias ...='dotdotdot'Fish
# Add to ~/.config/fish/config.fish
alias ... 'dotdotdot'Nobody should have to memorize:
tar -xvzfvstar -xvf— seriously, which one- every
dockerflag combo ffmpegsyntax — literally impossible- PowerShell's
Select-Stringvsgrepvsfindstr - 47 ways to check disk usage across 3 operating systems
findsyntax differences between macOS and Linux
You know what you want. ... knows how to say it.
bin/
dotdotdot.js CLI entry point & arg parser
lib/
colors.js Zero-dep ANSI color system
config.js Multi-provider config management
context.js OS, shell, git, tools detection
executor.js Command runner & error recovery
index.js Public API exports
llm.js 5 LLM providers, 2 prompt modes
menu.js Keyboard-driven selection menus
planner.js Multi-step task orchestrator
renderer.js Spinners, boxes, step indicators
safety.js Command risk analysis engine
session.js Session history & follow-ups
tokens.js Token usage tracking & cost estimates
ui.js Help screen, config view, setup wizard
Zero dependencies. Nothing to break, nothing to conflict.
Cross-platform. Windows, macOS, Linux — detects your shell and adapts.
Transparent. You always see the command before it runs.
Safe. Dangerous commands are flagged and blocked in auto-mode.
MIT — do whatever you want with it.

