Skip to content

Felipevieiraemp/cdx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

✻ cdx

A picker-wheel folder navigator for your terminal

Move between folders the way you scroll an iPhone alarm clock — visually, not by remembering paths.

License: MIT Platform Built with Bun TypeScript

Crafted by Noar.Company · MIT Licensed · Open Source


What is cdx

cd was designed for a world where you remembered every path. We don't live there anymore. We have a hundred projects, three drives, two cloud-synced home folders, a WSL mount, and a brain that forgot most of them five minutes ago.

cdx replaces cd with a visual picker. Open it from any prompt, scroll your folders like a wheel, type a few letters to fuzzy-find, hit Enter — your shell drops you exactly where you wanted to be.

It's the alarm-clock spinner from your phone, applied to filesystem navigation. The folders you visit most bubble to the top automatically (frecency, the algorithm zoxide popularized). A live preview shows you what's inside before you commit. The whole thing is one binary, zero runtime dependency, drop and run.

  ✻ cdx · Noar.Company Ai Solutions     A:  ›  2026 projetos  ›  cdx

  ╭─ drives ──╮  ╭─ folders ──────────────╮  ╭─ preview ────────╮
  │  ▮ A:      │  │     ..                  │  │  App.tsx         │
  │❯ ▮ C:      │  │  ❯  ✦ src/              │  │  PaneDrives.tsx  │
  │  ▮ D:      │  │     ✦ dist/             │  │  PaneFolders.tsx │
  │  ~ home    │  │       node_modules/     │  │  PanePreview.tsx │
  │            │  │       package.json      │  │  Shimmer.tsx     │
  ╰────────────╯  │       tsconfig.json     │  │  styles.ts       │
                  ╰─────────────────────────╯  ╰──────────────────╯
  ↑↓ navigate   → enter   ← back   ⏎ cd   tab focus   / search   esc quit

The wordmark ✻ cdx · Noar.Company Ai Solutions is animated — a warm gradient (coral → amber → gold → cream) shimmers through the letters left-to-right, like Claude Code's Prestidigitating….


Why this exists

Three pain points, one tool:

  1. cd is a memory test. Tab-completion only helps if you remember enough of the prefix. We forget. Visual navigation removes the requirement.
  2. zoxide is great until you don't know the name. Frecency works when you've been there before, but new projects mean blind navigation again.
  3. ranger/lf/broot are powerful but heavy. They're full file managers. We don't want to manage files. We want to get to a folder fast and let the shell do its thing.

cdx is the smallest possible thing that solves the actual problem: a focused picker, a wheel-spinner UX, frecency, fuzzy, preview, and that's it. One binary, no config required, install in 30 seconds.


Features

  • Wheel-picker navigation. Arrow keys are everything. Up/down spins the wheel; right enters; left backs out.
  • Cross-platform. Single self-contained binary for Windows, Linux, macOS, WSL. No Node, no Bun, no nothing.
  • Frecency ranking. Visited folders surface to top. Same algorithm zoxide uses — frequency × decay(age).
  • Fuzzy search. Type any letter to filter; matches highlighted in gold. Subsequence matcher with word-start bonuses.
  • Live preview. Selected folder's contents render in a side pane (lazy-loaded, debounced).
  • Multi-pane layout. Drives · folders · preview, side-by-side. Tab switches focus.
  • Animated wordmark. Yeah, a small thing, but it feels alive. Warm gradient shimmer.
  • Shell-agnostic. bash, zsh, fish, PowerShell — cdx init <shell> prints the wrapper.

Install

Pre-built binaries

Download from Releases and drop into a folder on your PATH.

Platform File
Windows x64 cdx.exe
Linux x64 cdx
macOS (planned)

From source

Requires Bun ≥ 1.3.

git clone https://github.com/Felipevieiraemp/cdx.git
cd cdx
bun install
bun run build           # produces dist/cdx.exe and dist/cdx

Setup

A child process can't change its parent shell's working directory. The standard trick (used by zoxide, fzf, lf) is a shell wrapper: cdx writes the chosen path; the wrapper calls cd. Run cdx init <shell> to print the wrapper for your shell:

bash / zsh

echo 'eval "$(cdx init bash)"' >> ~/.bashrc
# zsh users: replace bash with zsh and the file with ~/.zshrc

fish

cdx init fish | source
# Or persist:
cdx init fish > ~/.config/fish/conf.d/cdx.fish

PowerShell

cdx init powershell | Out-String | Invoke-Expression
# To persist, add the same line to your $PROFILE

After setup, just type cdx and the picker opens. Hit Enter on a folder and your shell jumps in.


Usage

cdx                  # open the picker at the current directory
cdx <query>          # open with a query pre-filled in the fuzzy filter
cdx --prune          # remove dead paths from the frecency database
cdx init <shell>     # print the shell wrapper (bash | zsh | fish | powershell)
cdx --help           # show all options

Keybindings

Key Action
move within active pane (wraps around)
enter the selected folder
go up one level (or delete a query character if searching)
Tab toggle focus between drives and folders
confirm — exits TUI and your shell jumps in
Esc clear the search; press again to cancel and quit
Ctrl+H toggle hidden files
Ctrl+N new folder — creates a folder inside the current directory and selects it
PgUp PgDn jump 10 entries
any letter start fuzzy filtering the current pane

Creating folders on the fly

A common dev workflow: navigate to a parent dir, spin up an isolated subfolder for a session, jump in. Press Ctrl+N from anywhere in the picker, type a name, hit Enter. The folder is created inside the current cwd, the cursor lands on it, and Enter again drops you in. Esc cancels.

+ new folder in projects: my-feature_

Validation rejects empty names, ., .., and the usual invalid filename characters (< > : " | ? * \ /). If a folder with that name already exists you get an already exists hint.


Design notes

The wheel-picker metaphor

Inspired by the iOS alarm time picker and bank-vault password dials. Each pane is a "wheel" — drives on the left, folders in the middle. Up/down spins the wheel, right enters the selection (changes wheels), left backs out. The metaphor handles the spatial reasoning for you: there's always a clear "current" item, a clear neighbor above, a clear neighbor below.

Frecency, not recency

Pure recency (most-recently-visited first) is wrong: you'll bounce a folder to the top by visiting it once, even if you never come back. Pure frequency is also wrong: yesterday's hot folder shouldn't outrank today's. The right answer is frecency: score = frequency × decay(age), exactly the formula zoxide uses.

age < 1 hour     →  multiplier × 4
age < 1 day      →  multiplier × 2
age < 1 week     →  multiplier × 0.5
older            →  multiplier × 0.25

Folders with a frecency record get a badge so you can see what cdx thinks is hot.

Sidecar file, not stdout

The naive way to communicate the chosen path back to the shell is stdout: cdx prints the path, the wrapper does d=$(cdx) && cd "$d". This works on bash. PowerShell 5.1 wraps every line of stderr from a native command in a NativeCommandError record — the TUI's escape codes turn into spam.

cdx avoids this entirely by writing the chosen path to a temp file referenced via the CDX_OUT_FILE environment variable. The wrapper sets the var, runs cdx (no output capture), reads the file. Same approach as lf and nnn.

Single binary, zero install

The build pipeline is bun build --compile --target=bun-windows-x64, which bundles the entire Bun runtime, your TypeScript, your dependencies, and your assets into a single executable. Roughly 110–120 MB on disk, but the user installs nothing. No Node, no global packages, no npm install -g. You drop the binary on PATH and it works.


Architecture

                       ┌─────────────────────┐
   keyboard input ───▶ │   bubbletea-style   │
                       │   Update / View     │ ◀──── frecency.Db
                       │   (Ink + React)     │ ◀──── filesystem
                       └─────────┬───────────┘
                                 │
                                 ▼
        ┌───────────┬─────────────────────┬────────────────┐
        │  drives   │     folders         │    preview     │
        │  PaneA    │     PaneB           │    PaneC       │
        └───────────┴─────────────────────┴────────────────┘
                                 │
                                 ▼
                          chosen path
                                 │
                                 ▼
                    write %TEMP%/cdx-out.tmp
                                 │
                                 ▼
                    shell wrapper does cd

The TUI runs as a stateful React tree on Ink, with useInput capturing keyboard events. Three panes share state through the root App component. Filesystem reads are async and aborted via alive flags when the user navigates away. The preview pane debounces by 100 ms to avoid thrashing the disk on fast cursor movement.


Configuration

The frecency database is plain JSON, persisted atomically (write-temp + rename):

OS Path
Windows %APPDATA%\cdx\db.json
Linux/macOS $XDG_DATA_HOME/cdx/db.json, falling back to ~/.local/share/cdx/db.json
{
  "version": 1,
  "entries": {
    "C:\\Users\\you\\projects": { "frequency": 12, "lastAccess": 1714680000 }
  }
}

Run cdx --prune to drop entries whose paths no longer exist on disk.


Tech stack

Layer Choice Why
Runtime + bundler + compiler Bun 1.3 TypeScript native, fast, --compile produces single binaries for any target
TUI framework Ink 5 React + Yoga flexbox in the terminal
Language TypeScript strict type-safe state machine, noUncheckedIndexedAccess
Tests bun test 19 tests covering listing, fuzzy ranking, frecency math

Project structure

cdx/
├── src/
│   ├── index.ts                  # CLI entry — args, subcommands, render
│   ├── tui/
│   │   ├── App.tsx               # root model — state machine, key handler
│   │   ├── PaneDrives.tsx        # left wheel — drives
│   │   ├── PaneFolders.tsx       # middle wheel — folders + fuzzy
│   │   ├── PanePreview.tsx       # right pane — lazy preview
│   │   ├── Shimmer.tsx           # animated wordmark component
│   │   └── styles.ts             # warm palette + glyphs
│   ├── fs/
│   │   ├── drives.ts             # cross-platform drive enumeration
│   │   ├── list.ts               # directory reading + sorting
│   │   └── fuzzy.ts              # subsequence matcher with bonuses
│   ├── frecency/
│   │   ├── score.ts              # zoxide-style scoring + bumping
│   │   └── store.ts              # atomic JSON persistence
│   └── shellinit/
│       └── index.ts              # bash / zsh / fish / pwsh wrappers
├── package.json
├── tsconfig.json
├── LICENSE
└── README.md

Development

bun install                        # one-time
bun run dev                        # run the TUI from source
bun test                           # 19 unit tests
bun run build:win                  # dist/cdx.exe
bun run build:linux                # dist/cdx
bun run build                      # both

When you change the wordmark animation or styles, hot-reload doesn't apply (it's a TUI, not a web app) — kill the running cdx and re-run bun run dev.


Roadmap

  • Global frecency picker mode (browse all known dirs, not just current cwd)
  • Named bookmarks / marks (jump to @work, @personal, …)
  • Custom keymap config file
  • Theme system (currently warm-only; cool/high-contrast variants)
  • macOS arm64 binary
  • Homebrew tap, scoop bucket, AUR
  • Symlink resolution display
  • Symlinked-folder expand inline

PRs welcome.


Inspiration

cdx stands on the shoulders of:

  • zoxide — frecency for cd (algorithm reused, gratefully)
  • fzf — fuzzy filtering UX, sidecar-file pattern
  • broot, ranger, lf — TUI navigators that proved this category mattered
  • The iPhone alarm wheel — the "scroll like time" interaction model
  • Claude Code — the warm-shimmer wordmark animation

Contributing

Issues and PRs welcome. The project is small and intentionally so — keep changes focused, write a test if you can, and follow the existing code style (TypeScript strict, no comments unless the why is non-obvious).

# fork, clone, branch
git checkout -b feature/your-thing

# develop
bun install
bun run dev
bun test

# submit
git push origin feature/your-thing
gh pr create

License

MIT © 2026 Noar.Company


About Noar.Company

cdx is one of the open source tools published by Noar.Company — a studio building thoughtful developer tooling and AI solutions. We believe terminals deserve craft.

noar.company

Made with ✻  ·  Open source  ·  Built to be small

About

A picker-wheel folder navigator for your terminal - by Noar.Company

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors