Jan Smrcka
Jan Smrcka

Full-stack Engineer

Full-time at ELI · Taking select contracts
Back

My CLI-First AI Development Workflow

I don't use VS Code with Copilot. I don't use Cursor. My entire AI-assisted development workflow runs in the terminal — and it's faster than any GUI setup I've tried.

Here's the stack and why it works.


The Stack

  • Tmux — session and window management
  • Claude Code / Open Code — AI coding agents in the terminal
  • Neovim — for when I need to edit manually
  • Git worktrees — the key to running parallel agents on one repo

Why CLI-First

GUI-based AI tools lock you into their editor. You get one agent, one context, one project at a time. In the terminal, everything is composable. Tmux gives each project its own isolated session, and I switch between them instantly with fuzzy search.

There's no waiting for an IDE to load, no extensions conflicting, no electron app eating 2GB of RAM per window.


Parallel Agents with Git Worktrees

This is the actual game changer.

The problem with running multiple AI agents on the same project is simple — they'll step on each other's files. If two agents are modifying the same codebase in the same directory, you get conflicts, corrupted state, and wasted time.

Git worktrees solve this cleanly. A worktree is a separate working directory linked to the same repository. Each worktree can have its own branch checked out, with its own set of files on disk, while sharing the same git history.

# Create worktrees for parallel work
git worktree add ../myproject-feature-auth feature/auth
git worktree add ../myproject-fix-api fix/api-validation

Now I have three directories, and each one gets its own tmux session:

myproject/                  # main session — Neovim, manual work
myproject-feature-auth/     # session 2 — Claude Code building auth flow
myproject-fix-api/          # session 3 — Open Code fixing API validation

Each agent runs in complete isolation. They can both read and write freely without interfering with each other. When they're done, I review each branch independently and merge.


Fast Switching with Fuzzy Search

The glue that holds this together is a small script I bound to Ctrl-f in tmux. It reads a list of root directories from a config file, finds all projects under them, and lets me fuzzy-search with fzf. Selecting a project either switches to its existing tmux session or creates a new one automatically.

#!/usr/bin/env bash
config_file="${TMUX_FUZZY_PATHS_FILE:-$HOME/.config/tmux-fuzzy-paths}"
[[ ! -f "$config_file" ]] && { printf 'Missing config: %s\n' "$config_file" >&2; exit 1; }
 
# Read root directories from config (one per line, supports ~ and comments)
roots=()
while IFS= read -r line || [[ -n "$line" ]]; do
  line="${line#"${line%%[![:space:]]*}"}" && line="${line%"${line##*[![:space:]]}"}"
  [[ -z "$line" || ${line:0:1} == "#" ]] && continue
  line="${line/#\~/$HOME}"
  [[ -d "$line" ]] && roots+=("$line")
done <"$config_file"
 
# Collect all project directories under configured roots
candidates=()
for root in "${roots[@]}"; do
  while IFS= read -r dir; do candidates+=("$dir"); done \
    < <(find "$root" -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
done
 
# Fuzzy search and create/switch tmux session
session=$(printf '%s\n' "${candidates[@]}" | awk '!seen[$0]++' | fzf || true)
[[ -z "$session" ]] && exit 0
session_name=$(basename "$session" | sed 's/[^A-Za-z0-9_-]/_/g')
 
if ! tmux has-session -t "$session_name" 2>/dev/null; then
  tmux new-session -s "$session_name" -c "$session" -d
fi
 
if [[ -n "${TMUX:-}" ]]; then
  tmux switch-client -t "$session_name"
else
  tmux attach-session -t "$session_name"
fi

The config file is just a list of directories to scan:

# ~/.config/tmux-fuzzy-paths
~/projects
~/work
~/oss

This means every git worktree I create automatically becomes a searchable, launchable session. Ctrl-f, type a few characters, hit enter — I'm in. No mental overhead tracking what's running where.


Reviewing Diffs Without Leaving the Terminal

One missing piece in a CLI workflow is a good diff viewer. git diff output is barely readable, but switching to an IDE just to review changes kills the flow. So I built differ — a terminal diff viewer with syntax highlighting, file navigation, and staging (GitHub). One tmux keybinding and I get a floating popup with everything I need to review and commit. No context switch.


When I Use Neovim

I use AI agents for about 90% of coding. But some things are faster by hand — small config tweaks, quick refactors where explaining the change to an agent takes longer than just doing it, or reviewing diffs before committing.

Neovim fits this workflow perfectly because it's already in the terminal. No context switch. I'm already in tmux, I just open a pane and edit.


The Workflow in Practice

  1. Start a tmux session for the project
  2. Create git worktrees for each task I want to parallelize
  3. Spin up an agent in each worktree
  4. Let them work while I review, test, or start another task
  5. Review the output of each agent on its branch
  6. Merge what's good, iterate on what isn't

The bottleneck in AI-assisted development is not the agent's speed — it's how many tasks you can run concurrently and how fast you can review the output. This setup maximizes both.


Tools