ogham/exa
A modern replacement for ‘ls’.
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓27+ active contributors
- ✓Distributed ownership (top contributor 41% of recent commits)
- ✓MIT licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Stale — last commit 2y ago
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/ogham/exa)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/ogham/exa on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ogham/exa
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ogham/exa shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- 27+ active contributors
- Distributed ownership (top contributor 41% of recent commits)
- MIT licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 2y ago
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ogham/exa
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ogham/exa.
What it runs against: a local clone of ogham/exa — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ogham/exa | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 620 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ogham/exa. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ogham/exa.git
# cd exa
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ogham/exa and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ogham/exa(\\.git)?\\b" \\
&& ok "origin remote is ogham/exa" \\
|| miss "origin remote is not ogham/exa (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/options/mod.rs" \\
&& ok "src/options/mod.rs" \\
|| miss "missing critical file: src/options/mod.rs"
test -f "src/fs/file.rs" \\
&& ok "src/fs/file.rs" \\
|| miss "missing critical file: src/fs/file.rs"
test -f "src/output/mod.rs" \\
&& ok "src/output/mod.rs" \\
|| miss "missing critical file: src/output/mod.rs"
test -f "src/fs/dir.rs" \\
&& ok "src/fs/dir.rs" \\
|| miss "missing critical file: src/fs/dir.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 620 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~590d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/ogham/exa"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
exa is a Rust-based command-line replacement for the Unix ls utility that displays file listings with enhanced features: terminal colors for file type distinction, Git integration (via git2), extended attributes support, symlink awareness, and grid/tree/long-format display modes. It ships as a single statically-linked binary and prioritizes speed and user-friendly defaults over strict POSIX compatibility. Single-binary architecture: src/main.rs is the entry point, with modular organization in src/fs/ (file/directory handling: dir.rs, file.rs, fields.rs, filter.rs) and src/info/ (file metadata: filetype.rs, sources.rs). Features are conditionally compiled (git support is optional via [features]). Build customization in build.rs; shell completions in completions/ (bash, fish, zsh); man pages in man/; dev tooling in devtools/.
👥Who it's for
Unix/Linux developers and power users who spend time on the command line and want faster, more colorful, more informative file listings than standard ls. Also relevant for DevOps engineers, sysadmins, and anyone using shell scripts that previously relied on ls.
🌱Maturity & risk
The project is unmaintained and superseded — the README explicitly directs users to the community fork eza (eza-community/eza). The codebase is well-structured and production-stable at v0.10.1, with CI via GitHub Actions (unit-tests.yml) and comprehensive shell completions, but the original maintainer is unreachable and the repository is not archived. This is mature code that is no longer actively developed.
High maintenance risk: single-maintainer project (Benjamin Sago) who is unreachable, and the repo itself is unmaintained in favor of the eza fork. Dependencies are modest (ansi_term, git2, zoneinfo_compiled, etc.) but git2 pulls in optional OpenSSL vendoring. The RUST-version constraint is 1.66.1 (2023 era), which may lag behind current Rust toolchains. For new projects, use eza instead; for existing exa codebases, plan a migration.
Active areas of work
The project is in maintenance-only mode. The last recorded state shows v0.10.1 released, with GitHub Actions running unit tests. No active development is happening — the codebase is feature-complete for its design goals. The community has moved to the eza fork (eza-community/eza) for bug fixes and new features.
🚀Get running
git clone https://github.com/ogham/exa.git
cd exa
cargo build --release
./target/release/exa --help
For development mode (faster builds without debug symbols per [profile.dev]): cargo build && ./target/debug/exa.
Daily commands:
Development: cargo build && ./target/debug/exa or use devtools/dev-run-debug.sh. Release: cargo build --release && ./target/release/exa or devtools/dev-run-release.sh. Test: cargo test (unit-tests.yml runs this on CI). Shell completions: source completions/{bash,fish,zsh}/exa for shell integration.
🗺️Map of the codebase
src/main.rs— Entry point that orchestrates CLI argument parsing, file system traversal, and output rendering—all new contributors must understand the top-level flow.src/options/mod.rs— Core options and flags parsing module that defines how exa interprets command-line arguments; essential for understanding feature gates and configuration.src/fs/file.rs— Represents a single file entity and its metadata (permissions, ownership, git status, xattrs); foundational for all file operations and output.src/output/mod.rs— Orchestrates all rendering modes (grid, details, tree, lines); critical for understanding how processed files become user-visible output.src/fs/dir.rs— Directory traversal and file collection logic; handles recursive listing and filtering—core to the recursive ls replacement behavior.Cargo.toml— Project manifest defining all dependencies (ansi_term, libc, users, git support); required reading for understanding external capabilities and MSRV.src/theme/mod.rs— Color and style theme management that bridges file metadata to visual presentation; key for understanding output customization.
🛠️How to make changes
Add a new output format/display mode
- Define a new variant in the output mode enum (typically in src/options/view.rs) (
src/options/view.rs) - Create a new renderer module (e.g., src/output/custom_format.rs) implementing the Display trait (
src/output/custom_format.rs) - Register the renderer in the output dispatcher (src/output/mod.rs) with a match arm (
src/output/mod.rs) - Add integration tests in xtests/ with expected output TOML files (
xtests/custom-format.toml)
Add a new file metadata field or column
- Add the field to the File struct in src/fs/file.rs (
src/fs/file.rs) - Create a renderer function in src/output/render/ (e.g., custom_field.rs) (
src/output/render/custom_field.rs) - Define a column type in src/fs/fields.rs and update column selection logic (
src/fs/fields.rs) - Integrate into the details output table (src/output/details.rs) (
src/output/details.rs)
Add a new filtering or sorting option
- Define new flags in src/options/flags.rs (
src/options/flags.rs) - Parse the flags in src/options/parser.rs (
src/options/parser.rs) - Implement filter logic in src/fs/filter.rs or sort logic in src/fs/dir.rs (
src/fs/filter.rs) - Update the options help text in src/options/help.rs (
src/options/help.rs)
Add support for a new file feature (like git or xattrs)
- Create a new feature module in src/fs/feature/ (e.g., src/fs/feature/custom_feature.rs) (
src/fs/feature/custom_feature.rs) - Integrate feature detection into File creation in src/fs/file.rs (
src/fs/file.rs) - Create a renderer in src/output/render/ to display the feature data (
src/output/render/custom_feature.rs) - Add feature flag in src/options/flags.rs to control visibility (
src/options/flags.rs)
🔧Why these technologies
- Rust with MSRV 1.66.1 — Provides memory safety and performance comparable to C while maintaining a modern, safe syntax. MSRV allows broad distribution across older systems.
- ansi_term 0.12 — Abstracts ANSI color and style codes for terminal output, enabling cross-platform colored text without manual escape sequence management.
- libc + users crate — Direct OS-level syscalls and user/group database lookups; essential for reading actual file permissions, ownership, and metadata on Unix systems.
- term_grid 0.2.0 — Handles automatic column alignment and wrapping for grid layout without reimplementing columnar formatting logic.
- scoped_threadpool 0.1 — Enables parallel file metadata collection (git status, xattrs) across multiple cores for faster listing of large directories.
⚖️Trade-offs already made
-
Single monolithic binary over pluggable modules
- Why: Simplicity and zero dependencies for end users; exa ships as 'just one single binary'.
- Consequence: Cannot be dynamically extended without recompilation; all features are built-in.
-
No async I/O; synchronous scoped_threadpool for parallelism
- Why: Simpler code structure for file system operations that are naturally blocking and I/O bound.
- Consequence: Not suitable for extremely high-concurrency scenarios; suitable for typical directory listing workloads.
-
Multiple hard-coded output modes (grid, details, tree, lines) rather than a plugin system
- Why: Reduces complexity and ensures tight integration with core rendering logic.
- Consequence: Adding new output modes requires modifying src/output/ and recompiling.
-
Git status detection built-in (src/fs/feature/git.rs) rather than delegated to external tool
- Why: Provides seamless, fast git awareness without spawning subprocesses.
- Consequence: exa is tightly coupled to git detection; any git library upgrade requires careful testing.
🚫Non-goals (don't propose these)
- Does not archive or compress files; view-only utility.
- Does not perform file operations (copy, move,
🪤Traps & gotchas
Git feature is optional but default-enabled: [features] shows git in default list; build with --no-default-features to exclude git2/OpenSSL. Unix-only user lookup: src/fs/file.rs uses [target.'cfg(unix)'.dependencies] users crate; Windows builds will not resolve user names. Threadpool: scoped_threadpool is single-threaded in std; num_cpus sets worker count but recursive directories share a pool — may not scale as expected on high-core systems. Locale-dependent sorting: uses locale crate; LS_LOCALE env var may affect order. Extended attributes (xattr) require filesystem support: src/fs/feature/xattr.rs silently skips if unavailable. build.rs runs at compile time: if it fails, the entire build fails; check error messages carefully.
🏗️Architecture
💡Concepts to learn
- Extended attributes (xattr) — exa can display file metadata beyond standard Unix mode bits (e.g., macOS Finder labels, SELinux contexts); implemented in src/fs/feature/xattr.rs and essential for system-level visibility.
- Git status integration — exa queries git2 to display which files are modified/staged/ignored in the listing; optional feature that enriches directory context without overhead if disabled.
- Terminal grid layout (term_grid) — exa's default -G display mode uses term_grid to auto-flow file entries into columns that fit the terminal width; critical for the modern, compact default UX.
- ANSI escape codes and ansi_term — exa colorizes output via ansi_term crate to distinguish file types (dirs=blue, symlinks=cyan, etc.); understanding ANSI sequences is required to modify color schemes.
- Scoped thread pooling for recursive traversal — exa uses scoped_threadpool to parallelize directory recursion (-R, -T modes); allows concurrent file system reads while keeping memory safe via Rust's borrow checker.
- Feature gates in Rust — exa demonstrates [features] in Cargo.toml to make git2 optional; allows slim builds for environments where git integration is unnecessary, reducing binary size and dependencies.
- Glob pattern matching for file filtering — exa implements --ignore-glob and respects .gitignore via glob crate; critical for the filtering UX and Unix shell compatibility.
🔗Related repos
eza-community/eza— Direct fork and maintained successor to exa; this is where bug fixes and new features are actively developed after the original maintainer became unreachable.BurntSushi/ripgrep— Similar philosophy: Rust CLI tool that replaces a Unix standard (grep) with better defaults, color output, and regex-first design; good architectural reference for high-performance CLI patterns.sharkdp/bat— Complements exa in modern CLI workflows: replaces cat with syntax highlighting; both tools target developers who want enhanced versions of classic Unix utilities.starship/starship— Consumes exa's output in shell prompts (shows git status, file counts); demonstrates exa's integration into modern terminal UX.tree-sitter/tree-sitter— Not directly related but exa does not use syntax parsing; tree-sitter is a potential future enhancement for smarter file type detection in display modes.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for Git feature (git2 dependency)
The repo has a git2 optional dependency and src/fs/feature/git.rs exists, but there are no visible integration tests validating Git status display in repositories. Given that Git integration is a key differentiator for exa (mentioned in README), this is a high-value gap. Tests should cover: showing git status in file listings, handling repositories with unstaged/staged changes, and performance with large repos.
- [ ] Create tests/git_integration_test.rs or add to a new tests/ directory
- [ ] Create test fixtures in devtools/ or tests/fixtures/ with sample git repositories
- [ ] Test Git status indicators with clean, dirty, and staged file scenarios
- [ ] Verify git feature works with --git flag (reference src/options/flags.rs for flag definitions)
- [ ] Run tests with and without git feature enabled (using feature flags in Cargo.toml)
Add Windows compatibility tests to CI (GitHub Actions)
The unit-tests.yml workflow currently only tests on Linux/macOS, but src/fs/file.rs and src/fs/mod.rs contain cross-platform file handling. exa uses libc and users crate which differ on Windows. The project could gain credibility by validating on Windows. This requires no new code, just CI configuration.
- [ ] Update .github/workflows/unit-tests.yml to add windows-latest matrix target
- [ ] Verify src/fs/file.rs works with Windows file attributes (uses libc which has Windows support)
- [ ] Check if users = "0.11" dependency works on Windows (it has platform-specific code)
- [ ] Document any Windows-specific limitations in README.md if needed
- [ ] Ensure build.rs compiles successfully on Windows
Add comprehensive tests for src/options/parser.rs
The parser.rs file handles all command-line argument parsing (referenced by main.rs and throughout src/options/), but no dedicated parser tests are visible in the repo. Given the complexity of option handling (filter.rs, flags.rs, view.rs all integrate here), this is a critical gap. Tests should cover flag combinations, conflicting options, and edge cases.
- [ ] Create tests/parser_tests.rs with unit tests for src/options/parser.rs
- [ ] Test valid flag combinations (e.g., --long --grid, --tree --grid-details)
- [ ] Test invalid/conflicting option handling (e.g., mutually exclusive flags)
- [ ] Test filter options from src/options/filter.rs (--ignore-glob, --git-ignore)
- [ ] Test theme/color options from src/options/theme.rs integration with parser
- [ ] Add regression tests for any previously reported parsing bugs
🌿Good first issues
- Add unit tests for src/fs/filter.rs: Currently no test coverage visible for glob filtering and gitignore logic; write tests for
--ignore-globand--git-ignorecombinations. - Document the color configuration schema: man/exa_colors.5.md exists but is minimal; add examples showing EXA_COLORS env var format and how to customize colors for specific file types.
- Add support for EXA_STRICT_MODE env var to warn on unsupported options: Create a compatibility mode that logs which ls options are not supported, helping users migrate scripts from ls to exa without silent failures.
⭐Top contributors
Click to expand
Top contributors
- @ariasuni — 41 commits
- @Tyrubias — 18 commits
- @TygrisIQ — 6 commits
- @cab-1729 — 4 commits
- @skyline75489 — 4 commits
📝Recent commits
Click to expand
Recent commits
3d1edbb— Remove Thank You button on README since it didn’t work anyway (ariasuni)753150d— Merge pull request #1249 from capak07/test#1010 (ariasuni)d7c9f4e— Removed Say Thanks link in README (capak07)fb05c42— exa is unmaintained, please use the active fork eza instead (ariasuni)f039202— Merge pull request #1188 from 1stDimension/ci-migrate (ariasuni)17893b5— Upgrade Rust version to fix CI (ariasuni)08cc56d— Merge pull request #1219 from MartinNowak/patch-1 (ariasuni)352d32b— Merge pull request #1178 from mtoohey31/fix/obsolete-icons (ariasuni)e79f736— Merge pull request #1175 from dcervenkov/patch-1 (ariasuni)a4cee84— fix fish completion for -i/--inode option (MartinNowak)
🔒Security observations
The exa project has a foundational security posture with Rust's memory safety guarantees, but faces significant concerns due to being unmaintained. The codebase itself appears relatively secure with no obvious injection vulnerabilities or hardcoded credentials. However, the lack of active maintenance means security dependencies will accumulate over time. The use of some older Rust versions (1.66.1) and deprecated crates (lazy_static) represents technical debt. Key areas of concern include path handling, Git integration security, and dependency management. Users should prioritize migrating to the maintained 'eza' fork or implementing an active maintenance and security update strategy.
- High · Outdated and Unmaintained Project —
README.md, Project metadata. The README explicitly states 'exa is unmaintained, use the fork eza instead.' This means the project will not receive security updates, bug fixes, or patches for newly discovered vulnerabilities. Dependencies will become stale over time. Fix: Consider migrating to the maintained fork 'eza' (https://github.com/eza-community/eza) or implement a maintenance plan for this fork. - Medium · Outdated Rust Edition with Pinned MSRV —
Cargo.toml (rust-version = '1.66.1'). The project targets Rust 1.66.1 (released Nov 2022) and uses edition 2021. While not critical, this older MSRV may miss important compiler-level security improvements and language features that prevent common vulnerabilities. Fix: Update the minimum supported Rust version (MSRV) to a more recent stable version (e.g., 1.75+) to benefit from security improvements in the compiler and standard library. - Medium · Dependency Version Pinning Concerns —
Cargo.toml [dependencies] section. Several dependencies use loose version constraints that could introduce breaking changes or vulnerabilities: ansi_term (0.12), git2 (0.13), lazy_static (1.3), and others. Without stricter version pinning, Cargo.lock may diverge across environments. Fix: Review and lock to specific patch versions in Cargo.lock. Consider usingcargo-auditregularly to check for known vulnerabilities in dependencies. Automate dependency updates with security scanning. - Low · Use of Deprecated lazy_static Crate —
Cargo.toml, lazy_static dependency. The project uses lazy_static (1.3) which is considered legacy. The Rust ecosystem has moved toward usingstd::sync::OnceLock(Rust 1.70+) or theonce_cellcrate as modern alternatives. Fix: Migrate from lazy_static to once_cell or std::sync::OnceLock to use more modern, actively-maintained solutions. - Low · Optional Git Support with Vendored OpenSSL —
Cargo.toml [features] section, git2 dependency. The optional 'vendored-openssl' feature for git2 bundles OpenSSL. Vendored dependencies can lag behind upstream security patches and create version fragmentation. Fix: Keep git2 dependency updated to the latest patch version. Prefer system OpenSSL when possible. Monitor CVE databases for git2 and OpenSSL vulnerabilities. - Low · No Input Validation Documentation —
src/fs/file.rs, src/fs/dir.rs, src/fs/feature/git.rs. The codebase processes file paths, Git metadata, and extended attributes without visible input sanitization patterns in the file structure. While Rust's memory safety helps, path traversal or encoding issues could exist. Fix: Audit path handling in src/fs/ modules to ensure symlinks and special filenames (e.g., paths with newlines, Unicode) are handled safely. Add comprehensive path validation and normalization. - Low · Extended Attributes and Git Feature Interaction —
src/fs/feature/git.rs, src/fs/feature/xattr.rs. The codebase includes optional Git and extended attributes (xattr) features. Interaction between these features and malformed metadata could lead to unexpected behavior or crashes. Fix: Test interaction between Git and xattr features with malformed repositories and files. Ensure graceful error handling and no information disclosure on failures.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.