# General Development Ubuntu Setup
A language-agnostic walkthrough for setting up a modern development environment on **Ubuntu 26.04 LTS (Resolute Raccoon)**, working identically on **Intel/AMD (`amd64`) and Arm (`arm64`)**. This is the Linux counterpart to [[General_Development_Mac_Tahoe_Setup]]. The pieces work together:
- **Ghostty** — the terminal emulator (what you see)
- **Starship** — the shell prompt (what tells you where you are)
- **Git** — version control (covered in Prerequisites)
- **GitHub CLI** — publishing repos from the command line (covered in Prerequisites)
- **VS Code** — the editor (Part 6)
- **Claude Code** — the AI, everywhere (Part 7)
Each layer is independently swappable, but together they form a fast, low-friction stack with a single AI surface across both terminal and editor.
Once this is complete, add language support by following the individual guides:
- [[Python_Development_Ubuntu_Setup]]
- [[C_Development_Ubuntu_Setup]]
- [[Ruby_Development_Ubuntu_Setup]]
- [[Go_Development_Ubuntu_Setup]]
- [[Rust_Development_Ubuntu_Setup]]
Each language guide assumes this general setup is already in place and only adds language-specific tooling.
> [!tip] AI assistance is optional
> Part 7 of this guide sets up Claude Code as an AI assistant. **You can skip Part 7 entirely** and still have a complete, professional dev environment from Parts 1–6. If you prefer a different AI tool (GitHub Copilot, Cursor, Continue, Cline, Aider), Part 7 includes pointers for adapting the setup to those instead.
> [!info] One architecture, one set of instructions
> Everything below is chosen to install the same way on both `amd64` and `arm64`. apt resolves the right package for your CPU automatically; the handful of tools installed via official scripts (Starship, uv, rustup, rv, Claude Code) detect your architecture themselves. You can confirm which architecture you're on at any time with `dpkg --print-architecture` (prints `amd64` or `arm64`) or `uname -m` (prints `x86_64` or `aarch64`).
---
## Prerequisites
Before starting, you should have:
- Ubuntu 26.04 LTS (Resolute Raccoon) on `amd64` or `arm64`, with a desktop session (these guides assume a GUI — Ghostty and the per-language GUI demos need a display)
- `sudo` access for your user
- A working network connection
First, bring the system fully up to date and install the handful of build basics the rest of the setup leans on:
```bash
sudo apt update && sudo apt upgrade -y
# Build basics + helpers used throughout this guide
sudo apt install -y build-essential curl wget git ca-certificates gnupg pkg-config
```
`build-essential` pulls in `gcc`, `g++`, `make`, and the headers needed to compile native code — several language toolchains (and a couple of tools below) expect a working C compiler.
### Why apt, not Homebrew?
The Mac guide uses Homebrew for everything. On Linux we use **apt** instead. apt is first-class on both `amd64` and `arm64`; Homebrew on Linux is only officially supported on `x86_64`, so it would break the "works on both architectures" goal the moment you spin up an Arm VM. For the few tools not packaged in apt, we use the projects' own architecture-aware installers.
### Configuring Git
Git is already installed from the prerequisites above. Set it up before doing anything else — these settings apply globally and only need to be set once per machine.
#### Identity
Every commit is stamped with a name and email. Use the same email you use for GitHub:
```bash
git config --global user.name "Your Name"
git config --global user.email "
[email protected]"
```
> [!tip] If you use multiple identities
> If you commit to both personal and work repos, you can override `user.email` per-repo later with `git config user.email "
[email protected]"` inside that repo's directory.
#### Modern defaults
These have all become standard in 2026 but aren't always the default in older Git:
```bash
# Use 'main' as the default branch name for new repos
git config --global init.defaultBranch main
# On 'git pull', fast-forward if possible; otherwise merge (don't rebase)
git config --global pull.rebase false
# On 'git push' for a new branch, automatically set upstream
git config --global push.autoSetupRemote true
# Colored output in status, diff, etc.
git config --global color.ui auto
# Use VS Code as the default editor for commit messages
# (We'll install VS Code in Part 6 — this line can be run now or later)
git config --global core.editor "code --wait"
```
#### Credential storage (libsecret)
macOS uses the Keychain. On Ubuntu desktop, the equivalent is the GNOME Keyring, reached through `libsecret`. Git ships the libsecret credential helper as source (not a prebuilt binary on Debian/Ubuntu), so you compile it once:
```bash
# Build deps for the helper
sudo apt install -y libsecret-1-0 libsecret-1-dev libglib2.0-dev
# Compile the helper that ships with git
sudo make -C /usr/share/doc/git/contrib/credential/libsecret
# Point git at the freshly built binary
git config --global credential.helper \
/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret
```
After this, HTTPS credentials (e.g. a GitHub personal access token) are stored in the keyring on first use and reused silently afterward.
> [!info] Headless or no keyring?
> If you're on a server with no GNOME Keyring running, swap the helper for the cross-platform fallback `git config --global credential.helper "cache --timeout=3600"` (keeps credentials in memory for an hour) or `store` (plaintext in `~/.git-credentials` — convenient but unencrypted). On a desktop, prefer libsecret.
#### Useful quality-of-life config
```bash
# Auto-correct obvious typos like 'git stauts' → 'git status'
git config --global help.autocorrect 20
# Prune deleted remote branches when fetching
git config --global fetch.prune true
# Show diff stats in commit message editor
git config --global commit.verbose true
# Better diff algorithm for code
git config --global diff.algorithm histogram
# Reuse conflict resolutions (magic — turn this on and forget about it)
git config --global rerere.enabled true
```
#### SSH key for GitHub
HTTPS with the credential helper works, but SSH is the conventional path for GitHub and avoids repeated auth prompts.
```bash
# Generate a new ED25519 key
ssh-keygen -t ed25519 -C "
[email protected]"
# Accept the default location (~/.ssh/id_ed25519) and set a passphrase
# Start the ssh-agent for this session
eval "$(ssh-agent -s)"
# Configure ~/.ssh/config so the agent loads your key automatically
cat >> ~/.ssh/config <<'EOF'
Host github.com
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
EOF
# Add the key to the agent
ssh-add ~/.ssh/id_ed25519
```
> [!info] Remembering your passphrase across reboots
> On macOS, `UseKeychain` stores the SSH passphrase in the Keychain. On Ubuntu desktop, GNOME Keyring's SSH agent does the same thing automatically the first time you `ssh` and check "remember." If you'd rather manage it yourself, the `keychain` package (`sudo apt install keychain`) keeps one agent alive across terminals — add `eval "$(keychain --eval --quiet id_ed25519)"` to `~/.bashrc`.
Now copy the public key to your clipboard and paste it at <https://github.com/settings/keys>. Clipboard tools differ by display server:
```bash
# Wayland (the Ubuntu 26.04 default session):
sudo apt install -y wl-clipboard
wl-copy < ~/.ssh/id_ed25519.pub
# X11 (if you switched to an Xorg session):
sudo apt install -y xclip
xclip -selection clipboard < ~/.ssh/id_ed25519.pub
```
> [!tip] Which display server am I on?
> Run `echo $XDG_SESSION_TYPE` — it prints `wayland` or `x11`. Ubuntu 26.04 defaults to Wayland. If a clipboard tool seems to do nothing, you're probably using the wrong one for your session.
Then test:
```bash
ssh -T
[email protected]
# Should say: "Hi yourusername! You've successfully authenticated..."
```
#### Verify
```bash
git config --global --list
```
Should show everything you just set. If you ever need to edit these by hand, they all live in `~/.gitconfig`.
### Publishing a repo to GitHub
`git` itself only manages local repositories and synchronization with remotes that already exist. It cannot create a new repository on GitHub's servers — that requires either the GitHub web UI or the `gh` CLI. The CLI is faster, scriptable, and keeps you in your terminal.
#### Install and authenticate GitHub CLI (one-time)
`gh` isn't in Ubuntu's default repos in a current-enough version, so add GitHub's official apt repository — it serves both `amd64` and `arm64`:
```bash
# Add GitHub CLI's apt repository (architecture-aware)
sudo mkdir -p -m 755 /etc/apt/keyrings
wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install -y gh
```
Then authenticate:
```bash
gh auth login
```
`gh auth login` walks through an interactive prompt. Recommended answers:
- **GitHub.com** (not Enterprise)
- **HTTPS** as the Git protocol (the libsecret helper stores the credentials)
- **Login with a web browser** (opens github.com, you paste a one-time code shown in the terminal, done)
After auth, configure `gh` as git's credential helper so plain `git push` works for HTTPS remotes:
```bash
gh auth setup-git
```
> [!info] SSH vs HTTPS for `gh`
> If you already set up SSH keys in the previous section, you can choose SSH during `gh auth login` instead. Either works. HTTPS is slightly less friction because `gh` manages the credentials automatically; SSH is the GitHub convention for daily work and what most tutorials assume.
#### Create a new GitHub repo from an existing local repo
From inside any directory that already has a local git repo with at least one commit:
```bash
gh repo create myproject --public --source=. --remote=origin --push
```
Flag breakdown:
| Flag | Purpose |
|------|---------|
| `myproject` | Name of the new GitHub repo (owner defaults to your authenticated username) |
| `--public` | Visibility. Use `--private` for private, `--internal` for org-only |
| `--source=.` | Use the current directory's existing local repo as the source |
| `--remote=origin` | Name the new remote "origin" (git convention) |
| `--push` | Push the current branch immediately after creating the remote |
Output looks like:
```
✓ Created repository yourusername/myproject on GitHub
✓ Added remote https://github.com/yourusername/myproject.git
✓ Pushed commits to https://github.com/yourusername/myproject.git
```
Verify by opening it in your browser:
```bash
gh repo view --web
```
#### The full new-project workflow
Here's the complete sequence any time you start a new project, combining your language toolchain, git, and GitHub:
```bash
# Create and initialize locally
mkdir -p ~/projects && cd ~/projects
mkdir myproject && cd myproject
# <language-specific init>
# Python: uv init --python 3.13
# Rust: cargo init
# Go: go mod init github.com/you/myproject
# Ruby: rv ruby pin 3.3
# C: touch main.c CMakeLists.txt
# Typical .gitignore (language-specific; each language guide covers what to add)
touch .gitignore
git init
git add .
git commit -m "Initial commit"
# Create on GitHub and push (assumes `gh` is authenticated)
gh repo create myproject --private --source=. --remote=origin --push
```
A few commands, and you have a fully configured project: local environment, git history, and a GitHub remote.
#### Day-to-day after the initial push
No more `gh` needed for routine work — standard git handles it:
```bash
# Edit files...
git add .
git commit -m "Add feature X"
git push
```
Because your `.gitconfig` has `push.autoSetupRemote = true` from the previous section, the first push on any new branch automatically sets the upstream tracking.
#### Alternative: plain git without `gh`
If you don't want to install `gh`, or you need to work with a non-GitHub host (Bitbucket, GitLab, a self-hosted Gitea instance, etc.), the manual path is:
**Step 1 — Create the empty repo on GitHub's web UI:**
1. Go to [github.com/new](https://github.com/new)
2. Enter the repository name
3. Choose Public or Private
4. **Leave all "Add a README/.gitignore/license" checkboxes unchecked** — otherwise you'll create a divergent history that's annoying to reconcile
5. Click "Create repository"
**Step 2 — Wire it up locally:**
```bash
# Using SSH (requires the SSH key setup above)
git remote add origin
[email protected]:yourusername/myproject.git
# Or using HTTPS
# git remote add origin https://github.com/yourusername/myproject.git
# Verify
git remote -v
# Push and set upstream
git push -u origin main
```
#### Useful `gh` commands
```bash
gh repo view
gh repo view --web
gh repo clone owner/name
gh repo list
gh pr create
gh pr list
gh issue create
gh issue list
gh auth status
```
---
## Part 1 — Installing Ghostty
### Install
Ghostty landed in the official Ubuntu repositories with 26.04, so the simplest install is just apt — and it resolves the correct `amd64`/`arm64` build for you:
```bash
sudo apt install -y ghostty
```
> [!info] Want a newer Ghostty than the repo ships?
> The version in the 26.04 repos can lag behind upstream. For the latest, add the official PPA instead (it builds for both architectures):
> ```bash
> sudo add-apt-repository -y ppa:ghostty-dev/stable
> sudo apt update
> sudo apt install -y ghostty
> ```
Launch it once from the Activities overview so the desktop registers it.
### Config file location
Ghostty reads a single key-value file at:
```
~/.config/ghostty/config
```
Create the directory and file if they don't exist:
```bash
mkdir -p ~/.config/ghostty
touch ~/.config/ghostty/config
```
> [!info] `~/.config/` is the standard location
> Ghostty follows the XDG convention. The directory usually already exists on a desktop Ubuntu install, but `mkdir -p` is harmless if it doesn't. Ghostty falls back to built-in defaults until a config file exists.
Reload config in-app with `Ctrl+Shift+,` after editing. No restart needed.
### Useful introspection commands
Before customizing, these commands show you what's available:
```bash
ghostty +list-themes
ghostty +list-fonts
ghostty +list-keybinds --default
ghostty +show-config --default --docs
```
### A recommended starter config
Paste this into `~/.config/ghostty/config`. It's the [[Ubuntu Linux/_resources/configs/ghostty-config|companion Ghostty config]], tuned for Linux. Comments explain each section.
```ini
# ── Appearance ────────────────────────────────────────────────
theme = Catppuccin Mocha
font-family = "MesloLGM Nerd Font Mono"
font-size = 12
window-padding-x = 12
window-padding-y = 12
window-padding-balance = true
background-opacity = 0.97
background-blur-radius = 20
# ── Cursor ────────────────────────────────────────────────────
cursor-style = block
cursor-style-blink = false
# Shell integration forces a bar cursor at prompts by default;
# this line preserves your cursor-style choice above.
shell-integration-features = no-cursor,sudo,title
# ── Linux / GTK ───────────────────────────────────────────────
gtk-titlebar = true
gtk-tabs-location = top
window-save-state = always
# ── Scrollback & clipboard ────────────────────────────────────
scrollback-limit = 10000
clipboard-read = allow
clipboard-write = allow
copy-on-select = clipboard
# ── Shell integration ─────────────────────────────────────────
# 'detect' lets Ghostty inject the right bits for bash/zsh/fish/nu
shell-integration = detect
# ── Quality-of-life keybinds ──────────────────────────────────
keybind = ctrl+shift+enter=toggle_split_zoom
keybind = ctrl+shift+o=new_split:right
keybind = ctrl+shift+e=new_split:down
keybind = ctrl+shift+w=close_surface
```
### Why each piece matters
> [!info] Font
> **MesloLGM Nerd Font Mono** includes programming glyphs (git branches, folder icons, language logos) that Starship uses. We install it in the next step. (Font size 12 is a touch smaller than the Mac guide's 14 — Linux font rendering tends to look a hair larger at the same nominal size; adjust to taste.)
> [!info] No `macos-option-as-alt` here
> That setting only exists on macOS. On Linux, `Alt` already behaves as `Alt` for word-wise motion (`Alt+B` / `Alt+F`), so there's nothing to fix.
> [!info] Keybinds use `Ctrl+Shift`
> The Mac config uses `Cmd`. Linux has no Command key, so the equivalents are bound to `Ctrl+Shift` (and these avoid clobbering the terminal's own `Ctrl+C`/`Ctrl+D`).
> [!info] `shell-integration = detect`
> Ghostty auto-injects shell integration code for **bash, zsh, fish, elvish, and nushell** — enabling Ctrl-click to jump to prompts, prompt markers, `ssh` terminfo handling, and more, with zero setup.
### Install the Nerd Font
Nerd Fonts aren't in apt, but the font files themselves are architecture-independent — the same files work on `amd64` and `arm64`. Install MesloLG into your user fonts directory:
```bash
mkdir -p ~/.local/share/fonts
cd /tmp
wget https://github.com/ryanoasis/nerd-fonts/releases/latest/download/Meslo.zip
unzip -o Meslo.zip -d ~/.local/share/fonts/Meslo
fc-cache -fv
```
Confirm the family is registered:
```bash
fc-list | grep -i "MesloLGM Nerd Font"
```
Alternatives you might prefer (download the matching zip from the [Nerd Fonts releases](https://github.com/ryanoasis/nerd-fonts/releases) page):
- `JetBrainsMono.zip` — clean, very popular
- `FiraCode.zip` — programming ligatures
- `Hack.zip` — dense, compact
Swap the `font-family` line in the config accordingly.
---
## Part 2 — Installing and Configuring Starship
### What Starship is
A cross-shell prompt written in Rust. It replaces the default bash prompt with one that shows **only what matters right now** — current directory, git branch/status, active language version (Python, Rust, Go, Ruby, Node, etc.), and more. It's fast enough to feel instantaneous, and it works identically on macOS and Linux.
### Install
Starship's official installer detects your architecture (`amd64`/`arm64`) automatically:
```bash
curl -sS https://starship.rs/install.sh | sh
```
> [!info] apt alternative
> Ubuntu also packages Starship (`sudo apt install starship`), but the repo version can lag behind upstream. The official installer above always gives you the current release for your CPU.
### Enable in bash
Ubuntu ships bash as the default shell. Add Starship's initialization to the **end** of `~/.bashrc`:
```bash
echo 'eval "$(starship init bash)"' >> ~/.bashrc
```
Then reload:
```bash
source ~/.bashrc
```
You should immediately see a new prompt. If glyphs look like boxes or question marks, your Ghostty font isn't a Nerd Font — revisit [[#Install the Nerd Font]] and confirm `font-family` in the Ghostty config.
### Configure
Starship's config file lives at:
```
~/.config/starship.toml
```
Create it with:
```bash
mkdir -p ~/.config
touch ~/.config/starship.toml
```
Paste in the [[Ubuntu Linux/_resources/configs/starship.toml|companion Starship config]] — it's identical to the Mac version, since Starship is cross-platform. A solid starting config for multi-language development:
```toml
# ── Overall format ────────────────────────────────────────────
# Two-line prompt: info on top, clean input line below.
format = """
$directory\
$git_branch\
$git_status\
$python\
$c\
$rust\
$golang\
$ruby\
$nodejs\
$cmd_duration\
$line_break\
$character"""
# Prompt character (the bit you actually type after)
[character]
success_symbol = "[❯](bold green)"
error_symbol = "[❯](bold red)"
vimcmd_symbol = "[❮](bold green)"
# Directory — keep it short
[directory]
truncation_length = 3
truncate_to_repo = true
style = "bold cyan"
# Git branch
[git_branch]
symbol = " "
style = "bold purple"
# Git status — dirty/clean indicators
[git_status]
style = "bold yellow"
format = '([\[$all_status$ahead_behind\]]($style) )'
# Language modules — each only shows when a relevant file is in the directory
[python]
symbol = " "
style = "bold yellow"
format = '[${symbol}${pyenv_prefix}(${version})(\($virtualenv\) )]($style)'
[c]
symbol = " "
style = "149 bold"
format = '[$symbol($version(-$name) )]($style)'
[rust]
symbol = " "
style = "bold red"
format = '[$symbol($version )]($style)'
[golang]
symbol = " "
style = "bold cyan"
format = '[$symbol($version )]($style)'
[ruby]
symbol = " "
style = "bold red"
format = '[$symbol($version )]($style)'
# How long the last command took (only shows if > 2s)
[cmd_duration]
min_time = 2000
style = "bold yellow"
format = "took [$duration]($style) "
# Hide things not relevant to most dev work
[aws]
disabled = true
[gcloud]
disabled = true
[nodejs]
detect_files = ["package.json"]
```
### Why the language modules matter
When you `cd` into a project directory, Starship detects the language based on files present and shows:
- **Python project** (has `.py`, `pyproject.toml`, or `.python-version`) → Python version + active venv
- **C project** (has `.c` or `CMakeLists.txt`) → Compiler version
- **Rust project** (has `Cargo.toml`) → Rust version
- **Go project** (has `.go` or `go.mod`) → Go version
- **Ruby project** (has `.rb`, `Gemfile`, or `.ruby-version`) → Ruby version
Reading the prompt left-to-right tells you at a glance what language and version you're working with. No `which python`, `go version`, `ruby -v`, or `rustc --version` — the prompt tells you before you type.
### Useful Starship commands
```bash
starship explain
starship print-config
starship module python
starship preset list
starship preset gruvbox-rainbow > ~/.config/starship.toml
```
---
## Part 3 — How It All Fits Together
Here's what a typical workflow looks like with the full stack:
```
┌─────────────────────────────────────────────────────────────┐
│ Ghostty (GPU-rendered GTK terminal, amd64 or arm64) │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ bash (Ubuntu default shell) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ Starship prompt │ │ │
│ │ │ ~/projects/demo main <lang version> │ │ │
│ │ │ ❯ <your commands> │ │ │
│ │ │ ┌───────────────────────────────────────────┐ │ │ │
│ │ │ │ Language toolchain (uv, cargo, go, etc.) │ │ │ │
│ │ │ └───────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### A day-in-the-life example
Regardless of which language guide you follow next, the pattern is the same:
```bash
# Create a new project
cd ~/projects
mkdir demo && cd demo
# <language-specific init> (uv init, cargo new, go mod init, etc.)
# Prompt shows: projects/demo <lang version> ❯
git init
git add .
git commit -m "Initial commit"
# After editing files, the prompt updates to show dirty state:
# projects/demo main [!] <lang version> ❯
# Commit, push, and the prompt returns to clean
git add . && git commit -m "Add feature X"
gh repo create demo --private --source=. --remote=origin --push
```
Every piece of the prompt has a job:
- **Directory** → where am I
- **Git branch + status** → what's the repo state
- **Language version** → which toolchain will run my next command
---
## Part 4 — Colors: Terminal vs Shell vs Prompt
A common point of confusion: **setting a Ghostty theme does not, by itself, control how `ls` colors directories, executables, and symlinks.** These are separate layers, and each one is configured independently.
### The three layers
| Layer | What it controls | Configured in |
|-------|------------------|---------------|
| **Terminal palette** | The 16 ANSI color slots + foreground/background. "When a program asks for color 34, render it as *this blue*." | Ghostty `theme = ...` |
| **File-type colors** | Which color `ls` uses for directories, symlinks, executables, etc. | `LS_COLORS` (via `dircolors`) or `eza` |
| **Syntax coloring at prompt** | Highlighting of commands as you type them (green = valid command, red = typo) | a bash line-editor add-on (ble.sh) |
> [!info] Good news for Linux: `ls` is colorful out of the box
> Unlike macOS (which ships BSD `ls`), Ubuntu uses **GNU coreutils**, and the default `~/.bashrc` already contains `alias ls='ls --color=auto'` plus a `dircolors` block. So directories show blue, executables green, and symlinks cyan with no extra work. The sections below are about *customizing* that, plus adding the command-line syntax highlighting that GNU `ls` doesn't provide.
### Customizing `ls` colors with `dircolors`
GNU `ls` reads the `LS_COLORS` environment variable. To customize it, generate a `dircolors` database, edit it, and source it from `~/.bashrc`:
```bash
# Write out the default database to edit
dircolors -p > ~/.dircolors
# Tell bash to load it (add to ~/.bashrc if not already present)
echo 'eval "$(dircolors -b ~/.dircolors)"' >> ~/.bashrc
source ~/.bashrc
```
Edit `~/.dircolors` to change, say, the color for directories (`DIR`) or specific extensions (`.tar`, `.jpg`). Each entry is a name plus an ANSI color code. This is the GNU equivalent of macOS's `LSCOLORS` string — more readable, and the same mechanism every Linux distro uses.
### Replacing `ls` with `eza` (recommended)
`eza` is a modern `ls` replacement with richer colors, a git-status column, and file-type icons. It's in apt:
```bash
sudo apt install -y eza
```
Then add to `~/.bashrc`:
```bash
alias ls='eza --group-directories-first --icons'
alias ll='eza -lah --group-directories-first --git --icons'
alias tree='eza --tree --level=3 --git-ignore --icons'
```
With `eza`, directories are colored, executables are colored, git status shows as an extra column (`N` = new, `M` = modified, `I` = ignored), and file-type icons appear next to filenames (requires the Nerd Font you installed in Part 1).
### Command coloring at the bash prompt with ble.sh
By default, commands you type into bash are all one color. zsh users get this from `zsh-syntax-highlighting` and `zsh-autosuggestions` — but those are zsh-only. The bash equivalent is **ble.sh** (Bash Line Editor), which provides both:
- **Green** for valid commands on your `PATH`, **red** for typos / unknown commands
- **Grey ghost text** suggesting completions from history (press `→` to accept)
- Plus better multi-line editing and vim/emacs modes
Install it (it's pure bash + a build step; needs `git`, `make`, and `gawk`, all already present):
```bash
sudo apt install -y gawk
git clone --recursive --depth 1 https://github.com/akinomyoga/ble.sh.git /tmp/ble.sh
make -C /tmp/ble.sh install PREFIX=~/.local
```
Then wire it into `~/.bashrc`. ble.sh has a specific two-line pattern — one line **near the top**, one **at the very end**:
```bash
# --- Near the TOP of ~/.bashrc (before other interactive setup) ---
[[ $- == *i* ]] && source ~/.local/share/blesh/ble.sh --attach=none
# ... the rest of your ~/.bashrc (aliases, starship init, etc.) ...
# --- At the very END of ~/.bashrc ---
[[ ! ${BLE_VERSION-} ]] || ble-attach
```
Reload with `source ~/.bashrc` (or just open a new Ghostty window). You'll immediately see:
```
❯ git status ← all green (valid commands + args)
❯ gti status ← "gti" in red (typo)
❯ git sta ← "git" green, "sta" grey ghost text (press → to accept "status")
```
> [!warning] ble.sh ordering matters
> The `source ... --attach=none` line must come **before** Starship's `eval "$(starship init bash)"`, and `ble-attach` must be the **last** interactive line in `~/.bashrc`. ble.sh integrates with Starship automatically when loaded in this order.
### Testing your color setup
To confirm Ghostty is rendering the full 256-color palette correctly:
```bash
# Quick 16-color test
for i in {0..15}; do printf "\e[48;5;${i}m %2d \e[0m" "$i"; done; echo
# 256-color test (nice gradient)
for i in {0..255}; do printf "\e[48;5;${i}m \e[0m"; done; echo
# True color (24-bit) test
awk 'BEGIN{ for (i=0; i<77; i++) { r=255-(i*255/76); g=(i*510/76); b=(i*255/76); if (g>255) g=510-g; printf "\033[48;2;%d;%d;%dm ", r,g,b } printf "\033[0m\n" }'
```
If all three produce smooth color strips, Ghostty supports full truecolor out of the box.
### Summary of what you get from each piece
| Result | Requires |
|--------|----------|
| A dark, pleasant background and nice base colors | Ghostty `theme = Catppuccin Mocha` |
| `git status` showing red/green for changes | Nothing — git emits ANSI, Ghostty renders it |
| `ls` showing blue directories, green executables | Nothing — GNU `ls --color=auto` is on by default |
| Customized `ls` colors | `dircolors` + `LS_COLORS` |
| File-type icons next to filenames | `eza --icons` + a Nerd Font |
| Green/red coloring as you type commands | ble.sh |
| Grey ghost-text command suggestions | ble.sh |
| `~/projects/demo main 3.13.2` prompt | Starship + Nerd Font |
The theme is just the paint palette. The shell tells each tool which colors to reach for.
---
## Part 5 — Optional Enhancements
### Modern CLI replacements
```bash
sudo apt install -y eza bat ripgrep fd-find fzf zoxide direnv
```
> [!warning] Debian/Ubuntu renames two of these binaries
> To avoid clashes with unrelated existing commands, Ubuntu ships **`bat` as `batcat`** and **`fd-find` as `fdfind`**. Add aliases (or symlinks) so the usual names work:
> ```bash
> mkdir -p ~/.local/bin
> ln -sf "$(command -v batcat)" ~/.local/bin/bat
> ln -sf "$(command -v fdfind)" ~/.local/bin/fd
> ```
> Make sure `~/.local/bin` is on your `PATH` (Part 7 adds it for Claude Code; if you're not doing Part 7, add `export PATH="$HOME/.local/bin:$PATH"` to `~/.bashrc`).
Then add to `~/.bashrc`:
```bash
# Modern replacements
alias ls='eza --group-directories-first'
alias ll='eza -lah --group-directories-first --git'
alias tree='eza --tree --level=3 --git-ignore'
alias cat='bat --style=plain'
# zoxide (smarter cd — learns your most-visited dirs)
eval "$(zoxide init bash)"
alias cd='z'
# fzf (fuzzy finder — powers Ctrl+R history, Ctrl+T file picker)
eval "$(fzf --bash)"
```
After running this, `Ctrl+R` becomes a fuzzy-searchable command history, and `z proj` jumps to the most-used directory matching "proj".
> [!info] `fzf --bash` needs a current fzf
> The `fzf --bash` integration shipped in fzf 0.48+. Ubuntu 26.04's `fzf` is new enough. On older systems you'd source `/usr/share/doc/fzf/examples/key-bindings.bash` instead.
### direnv — auto-activate per-project environments
`direnv` was installed above. Hook it into bash:
```bash
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
```
direnv reads an `.envrc` file in a project directory and loads it whenever you `cd` in, then unloads it when you leave — so each project gets its own environment (a Python virtualenv, toolchain env vars, a project-local `PATH`) with no manual activation. After creating an `.envrc`, run `direnv allow` once to trust it.
The contents of `.envrc` are language-specific. Each language setup guide has a ready-to-use example: [[Python_Development_Ubuntu_Setup]], [[Go_Development_Ubuntu_Setup]], [[Rust_Development_Ubuntu_Setup]], [[Ruby_Development_Ubuntu_Setup]], and [[C_Development_Ubuntu_Setup]].
---
## Part 6 — Visual Studio Code
### Install
Add Microsoft's official apt repository — it carries `amd64`, `arm64`, and `armhf` builds, so the same steps work on any Ubuntu VM:
```bash
# Microsoft GPG key + repo
wget -qO- https://packages.microsoft.com/keys/microsoft.asc \
| gpg --dearmor | sudo tee /etc/apt/keyrings/packages.microsoft.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/packages.microsoft.gpg
echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" \
| sudo tee /etc/apt/sources.list.d/vscode.list > /dev/null
sudo apt update
sudo apt install -y code
```
This installs VS Code and the `code` CLI shim, so you can open files and folders from Ghostty:
```bash
code .
code myfile.py
code -d old.py new.py
```
> [!info] Why the apt repo, not Snap?
> Ubuntu also offers VS Code as a Snap (`sudo snap install code --classic`), which works on both architectures too. The apt repo is preferred here because it integrates with `apt upgrade` alongside the rest of your stack and avoids Snap's confinement quirks (slower first launch, occasional issues with the integrated terminal's environment). Either is fine; pick one.
### Essential general-purpose extensions
Install these from the command line so they're reproducible. These apply regardless of which languages you work in:
```bash
# Better TOML (for editing pyproject.toml, Cargo.toml, starship.toml)
code --install-extension tamasfe.even-better-toml
# YAML (for GitHub Actions, docker-compose, Kubernetes)
code --install-extension redhat.vscode-yaml
# GitLens — richer git integration than the built-in
code --install-extension eamodio.gitlens
# EditorConfig — respects .editorconfig files in projects
code --install-extension editorconfig.editorconfig
```
Language-specific extensions are covered in each language's individual setup guide.
### Configure VS Code — `settings.json`
On Linux, VS Code stores its user settings at:
```
~/.config/Code/User/settings.json
```
Open it from inside VS Code via `Ctrl+Shift+P` → "Preferences: Open User Settings (JSON)". Paste in the [[Ubuntu Linux/_resources/configs/vscode-settings.json|companion VS Code settings]], or merge with:
```json
{
// ── Editor appearance ─────────────────────────────────────
"editor.fontFamily": "'MesloLGM Nerd Font Mono', 'Ubuntu Mono', monospace",
"editor.fontSize": 13,
"editor.fontLigatures": false,
"editor.lineNumbers": "on",
"editor.renderWhitespace": "boundary",
"editor.rulers": [100],
"editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs": "active",
"editor.minimap.enabled": false,
"editor.cursorBlinking": "solid",
// ── Editor behavior ───────────────────────────────────────
"editor.formatOnSave": true,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
// ── Terminal (integrated) ─────────────────────────────────
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.fontFamily": "'MesloLGM Nerd Font Mono'",
"terminal.integrated.fontSize": 13,
"terminal.integrated.cursorBlinking": false,
"terminal.integrated.cursorStyle": "block",
"terminal.integrated.inheritEnv": true,
// ── Files & search ────────────────────────────────────────
"files.exclude": {
"**/.git": false
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/build": true,
"**/target": true,
"**/.venv": true
},
// ── Git ───────────────────────────────────────────────────
"git.autofetch": true,
"git.confirmSync": false,
"git.enableSmartCommit": true,
"git.suggestSmartCommit": false,
// ── Workbench & theme ─────────────────────────────────────
"workbench.colorTheme": "Default Dark Modern",
"workbench.iconTheme": "vs-seti",
"workbench.startupEditor": "none",
"workbench.editor.enablePreview": false,
// ── Telemetry ─────────────────────────────────────────────
"telemetry.telemetryLevel": "off",
// ── AI: disable built-in AI features ──────────────────────
// This disables Copilot prompts and any built-in AI so Claude Code
// is the only AI surface. See Part 7 for the rationale.
"chat.disableAIFeatures": true
}
```
### Why each block matters
> [!info] Font matching
> Using the same **MesloLGM Nerd Font Mono** as Ghostty means your integrated terminal inside VS Code looks identical to your standalone Ghostty windows. The fallback `'Ubuntu Mono'` covers the case where the Nerd Font isn't found.
> [!info] `terminal.integrated.defaultProfile.linux: bash`
> This is the Linux equivalent of the Mac config's `...osx: zsh`. It makes VS Code's integrated terminal open bash — the same shell (with the same Starship prompt and ble.sh) you use in Ghostty.
> [!info] Language-specific settings go in per-language guides
> `settings.json` supports language-scoped blocks like `"[python]": { ... }` that only apply to that language's files. Each language guide adds its own block to this file. They don't conflict.
---
## Part 7 — Claude Code as the Only AI (Ghostty + VS Code)
> [!important] AI assistance is entirely optional
> **Everything in Parts 1–6 stands on its own.** Ghostty, Starship, Git, GitHub CLI, VS Code with language extensions, linters, formatters, and debuggers form a complete professional development environment. You can stop after Part 6 and have a fully functional setup. Skip this part entirely if you don't want an AI in your workflow, or come back to it later.
> [!note] If you use a different AI tool
> This guide configures Claude Code specifically. **The general principle — install your AI of choice, configure VS Code so it doesn't fight other AI tools — still applies, but the specific commands differ.** Quick pointers for the major alternatives:
>
> - **GitHub Copilot**: Install via the `github.copilot` and `github.copilot-chat` VS Code extensions. Sign in through VS Code's GitHub account integration. **Remove `"chat.disableAIFeatures": true` from settings.json** — Copilot uses VS Code's built-in chat UI that this setting hides.
> - **Cursor**: Cursor is a separate editor (a fork of VS Code). It ships Linux `amd64`/`arm64` AppImage builds from cursor.com. Your VS Code extension list and settings.json mostly port over.
> - **Continue**: Open-source, multi-provider. Install the `continue.continue` VS Code extension and configure your model provider (Anthropic API, OpenAI, local Ollama, etc.).
> - **Cline**: Install the `saoudrizwan.claude-dev` VS Code extension; bring your own API key.
> - **Aider**: Terminal-based, like Claude Code. Install with `uv tool install aider-chat` and configure with your provider's API key.
>
> Whichever you pick, the "uninstall competing extensions" advice still applies: pick one AI surface and remove the others.
This section sets up Claude Code so it's your single AI surface across both the terminal (Ghostty) and the editor (VS Code).
### What you're setting up
| Surface | How Claude Code appears |
|---------|-------------------------|
| **Ghostty** | Run `claude` inside any project directory → interactive terminal agent with file edits, shell commands, git operations |
| **VS Code** | Spark icon in Activity Bar → sidebar chat with inline diffs, `@`-file mentions, plan mode, accept/reject buttons |
Both surfaces share the **same auth**, **same `~/.claude/` config**, and **same `CLAUDE.md` project files**.
### Prerequisites
- An **Anthropic account** with access to Claude Code. Claude Pro or Claude Max is the straightforward path; API credits via Anthropic Console also work.
- **VS Code** (covered in Part 6).
- **Ghostty** (covered in Part 1).
> [!warning] The free Claude.ai plan does not include Claude Code
> Any paid Claude subscription (Pro, Max, Teams, Enterprise) does, and so does Anthropic Console with API credits.
### Install Claude Code
Anthropic ships a **native binary** as the recommended install — no Node.js dependency, auto-updates in the background, and the installer detects your architecture (`amd64`/`arm64`):
```bash
curl -fsSL https://claude.ai/install.sh | bash
```
The binary lands at `~/.local/bin/claude`. Make sure that directory is on your PATH by adding this to `~/.bashrc`:
```bash
export PATH="$HOME/.local/bin:$PATH"
```
Then `source ~/.bashrc` and verify:
```bash
which claude
claude --version
```
> [!info] Why not apt?
> There's no official apt package for Claude Code. The native installer auto-updates silently in the background, which is what you want for an AI tool that improves weekly. The npm method (`npm install -g @anthropic-ai/claude-code`) still works but is deprecated — Anthropic recommends against it now. The native install supports Ubuntu 20.04+ on both architectures.
### First-run authentication
From Ghostty, in any project directory:
```bash
cd ~/projects
claude
```
On first launch Claude Code opens a browser window for OAuth login. Sign in with the same Anthropic account as your Claude Pro/Max subscription. The token is saved to `~/.claude/` and reused across both Ghostty and VS Code.
### Using Claude Code in Ghostty
Inside any project, start a session with `claude`. Useful built-in commands:
```
/help List all slash commands
/init Generate a CLAUDE.md for this project (do this first!)
/clear Clear conversation context
/rewind Restore to a checkpoint (undo Claude's changes)
/plugins Browse and install plugins
/terminal-setup Auto-configure Shift+Enter for multi-line prompts
/exit Leave the session
```
Claude can read and edit files, run shell commands (with your permission per-command), use `git`, and manage its context automatically. Every code change is checkpointed — press **Esc twice** or run `/rewind` to undo.
> [!tip] Make CLAUDE.md your first step in any project
> `/init` scans your project and writes a `CLAUDE.md` with project structure, conventions, and commonly-used commands. Claude loads this file at the start of every session. Commit it to git so it's shared with anyone else working on the repo.
### Installing the VS Code extension
**Path A — From inside VS Code (recommended):**
1. `Ctrl+Shift+X` to open Extensions
2. Search **"Claude Code"** — install the one published by **Anthropic** (avoid look-alikes)
3. Reload VS Code if prompted
**Path B — From Ghostty:**
```bash
code --install-extension anthropic.claude-code
```
Or just run `claude` inside a VS Code integrated terminal once — Claude Code auto-installs its extension when it detects a VS Code environment.
### First use in VS Code
After install, you'll see new UI elements: a **Spark icon** in the Activity Bar (left sidebar), a **Spark icon** in the top-right editor toolbar, and **"✱ Claude Code"** in the status bar. Click any of them; first launch reuses the same Anthropic auth as the CLI.
Once signed in:
- Type into the prompt box at the bottom of the sidebar
- `@filename` to attach specific files as context
- Highlight code → right-click → "Add to Claude Code context"
- Changes appear as **inline diffs** — accept per-hunk or per-file
### Making Claude Code the only AI
**1. Disable VS Code's built-in AI** (done in Part 6 via `settings.json`):
```json
"chat.disableAIFeatures": true
```
**2. Don't install (or uninstall) competing extensions:**
```bash
code --uninstall-extension github.copilot
code --uninstall-extension github.copilot-chat
code --uninstall-extension continue.continue
code --uninstall-extension saoudrizwan.claude-dev
code --uninstall-extension sourcegraph.cody-ai
```
**3. In Ghostty, don't wire in competing CLIs.** Claude Code is sufficient — avoid installing Aider, Gemini CLI, or similar alongside it if the goal is a single AI.
### Ghostty vs VS Code — when to use which
| Use **Ghostty + `claude`** when | Use **VS Code extension** when |
|---------------------------------|--------------------------------|
| Exploring a new repo you haven't opened yet | Reviewing changes with inline diffs |
| Bulk refactors spanning many files | Editing a specific function with tight feedback |
| Running tests/builds interactively | Using `@mentions` to pull specific files into context |
| SSH'd into a remote machine | You want to pair with Claude while you edit |
They aren't mutually exclusive — it's common to have `claude` running in a Ghostty pane while VS Code is open on the same project.
### Useful extras
**Multi-line prompts in VS Code's integrated terminal** — run this once inside Claude Code:
```
/terminal-setup
```
**Checkpoints** — Claude automatically checkpoints before each change. Undo with `Esc` twice (in terminal) or `/rewind`. Checkpoints only cover Claude's edits — keep using git commits for the real backup.
---
## Troubleshooting
> [!warning] Glyphs show as boxes or `?` in the prompt
> Your font isn't a Nerd Font. Reinstall it (Part 1) and confirm `font-family = "MesloLGM Nerd Font Mono"` in `~/.config/ghostty/config`, then run `fc-cache -fv`.
> [!warning] Ghostty won't launch / shows a GTK or GL error
> Ghostty needs GPU/GL access. In a VM, make sure 3D acceleration is enabled in the hypervisor (VirtualBox/VMware/UTM) or use a virtio-gpu display. As a fallback you can run any other terminal and still use the rest of this stack — the shell config is what matters.
> [!warning] `command not found` for a tool right after installing
> Open a new Ghostty window or run `source ~/.bashrc`. If a tool installed to `~/.local/bin` (Claude Code, uv tools) still isn't found, confirm `export PATH="$HOME/.local/bin:$PATH"` is in `~/.bashrc`.
> [!warning] `bat`/`fd` say "command not found" but they're installed
> On Ubuntu they're `batcat`/`fdfind`. Create the aliases/symlinks shown in Part 5.
> [!warning] ble.sh broke my prompt or pasting
> Confirm the ordering: `source ... --attach=none` near the top of `~/.bashrc`, `ble-attach` as the very last line, and `starship init bash` between them. If something's badly broken, comment out the two ble.sh lines and reload to get a clean bash.
> [!warning] `git push` asks for username/password every time
> You're using HTTPS without a working credential helper. Either set up the libsecret helper (Prerequisites → Credential storage) or run `gh auth setup-git`, or switch the remote to SSH.
> [!warning] Starship language version not showing
> Starship only shows a language module when it detects a matching project — you need the relevant file (e.g. `pyproject.toml`, `go.mod`, `Cargo.toml`) in the directory. This is intentional, to avoid clutter.
> [!warning] `claude: command not found` after install
> The native installer puts the binary at `~/.local/bin/claude`. Add `export PATH="$HOME/.local/bin:$PATH"` to `~/.bashrc` and `source` it. A stale npm install can shadow the native binary — check with `which -a claude`.
---
## Summary — the complete install sequence
> [!warning] This is a checklist, not a script
> The block below is **not a shell script you can save and run.** It's a numbered sequence of commands to **copy and paste into Ghostty (or GNOME Terminal) one block at a time**, in order. Several steps depend on the previous one having finished, and three steps require you to **manually edit files** before continuing:
>
> - **Step 11** asks you to paste the recommended **Ghostty config** into `~/.config/ghostty/config`
> - **Step 11** also asks you to paste the recommended **Starship config** into `~/.config/starship.toml`
> - **Step 11** also asks you to paste the recommended **VS Code settings** into `~/.config/Code/User/settings.json`
> - **Step 9** asks you to add the **ble.sh two-line pattern** to `~/.bashrc`
>
> Two later steps (12 — `gh auth login`; 13 — `claude` first run) **open a browser window** and require you to complete OAuth login interactively before continuing.
```bash
# 1. Update + build basics
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential curl wget git ca-certificates gnupg pkg-config gawk unzip
# 2. Core CLI tools (note: bat→batcat, fd-find→fdfind)
sudo apt install -y eza bat ripgrep fd-find fzf zoxide direnv
# 3. Terminal
sudo apt install -y ghostty
# 4. Nerd Font
mkdir -p ~/.local/share/fonts && cd /tmp
wget https://github.com/ryanoasis/nerd-fonts/releases/latest/download/Meslo.zip
unzip -o Meslo.zip -d ~/.local/share/fonts/Meslo && fc-cache -fv
# 5. GitHub CLI (official apt repo)
sudo mkdir -p -m 755 /etc/apt/keyrings
wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update && sudo apt install -y gh
# 6. VS Code (official apt repo)
wget -qO- https://packages.microsoft.com/keys/microsoft.asc \
| gpg --dearmor | sudo tee /etc/apt/keyrings/packages.microsoft.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/packages.microsoft.gpg
echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" \
| sudo tee /etc/apt/sources.list.d/vscode.list > /dev/null
sudo apt update && sudo apt install -y code
# 7. Starship (official installer — architecture-aware)
curl -sS https://starship.rs/install.sh | sh
# 8. ble.sh (bash syntax highlighting + autosuggestions)
git clone --recursive --depth 1 https://github.com/akinomyoga/ble.sh.git /tmp/ble.sh
make -C /tmp/ble.sh install PREFIX=~/.local
# 9. Git config (REPLACE name/email)
git config --global user.name "Your Name"
git config --global user.email "
[email protected]"
git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global push.autoSetupRemote true
git config --global color.ui auto
git config --global core.editor "code --wait"
git config --global fetch.prune true
git config --global commit.verbose true
git config --global diff.algorithm histogram
git config --global rerere.enabled true
git config --global help.autocorrect 20
# Credential helper (compile libsecret once):
sudo apt install -y libsecret-1-0 libsecret-1-dev libglib2.0-dev
sudo make -C /usr/share/doc/git/contrib/credential/libsecret
git config --global credential.helper \
/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret
# 10. General-purpose VS Code extensions
code --install-extension tamasfe.even-better-toml
code --install-extension redhat.vscode-yaml
code --install-extension eamodio.gitlens
code --install-extension editorconfig.editorconfig
# 11. Claude Code (native installer — architecture-aware)
curl -fsSL https://claude.ai/install.sh | bash
code --install-extension anthropic.claude-code
# 12. Wire up ~/.bashrc — add these lines.
# IMPORTANT: ble.sh has a top line and a bottom line (see Part 4).
# Near the TOP of ~/.bashrc:
# [[ $- == *i* ]] && source ~/.local/share/blesh/ble.sh --attach=none
# Then (anywhere after, in this order):
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
mkdir -p ~/.local/bin
ln -sf "$(command -v batcat)" ~/.local/bin/bat
ln -sf "$(command -v fdfind)" ~/.local/bin/fd
echo 'eval "$(starship init bash)"' >> ~/.bashrc
echo 'eval "$(zoxide init bash)"' >> ~/.bashrc
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
echo 'eval "$(fzf --bash)"' >> ~/.bashrc
echo "alias ls='eza --group-directories-first --icons'" >> ~/.bashrc
echo "alias ll='eza -lah --group-directories-first --git --icons'" >> ~/.bashrc
echo "alias tree='eza --tree --level=3 --git-ignore --icons'" >> ~/.bashrc
echo "alias cat='bat --style=plain'" >> ~/.bashrc
echo "alias cd='z'" >> ~/.bashrc
# At the VERY END of ~/.bashrc:
echo '[[ ! ${BLE_VERSION-} ]] || ble-attach' >> ~/.bashrc
# 13. Paste the Ghostty / Starship / VS Code configs into place
# (see Parts 1, 2, and 6 for the recommended contents)
mkdir -p ~/.config/ghostty ~/.config
touch ~/.config/ghostty/config ~/.config/starship.toml
# 14. Authenticate GitHub CLI (interactive — HTTPS, browser login)
gh auth login
gh auth setup-git
# 15. First launch of Claude Code (interactive OAuth in browser)
# Run `claude` in Ghostty — a browser window opens for login.
```
Open a fresh Ghostty window, and you're done with the general setup. Pick a language guide to continue:
- [[Python_Development_Ubuntu_Setup]]
- [[C_Development_Ubuntu_Setup]]
- [[Ruby_Development_Ubuntu_Setup]]
- [[Go_Development_Ubuntu_Setup]]
- [[Rust_Development_Ubuntu_Setup]]
---
## Related notes
**Same setup on macOS:**
- [[General_Development_Mac_Tahoe_Setup]] — the Apple Silicon counterpart to this guide
**Language-specific setup (build on this general guide):**
- [[Python_Development_Ubuntu_Setup]]
- [[C_Development_Ubuntu_Setup]]
- [[Ruby_Development_Ubuntu_Setup]]
- [[Go_Development_Ubuntu_Setup]]
- [[Rust_Development_Ubuntu_Setup]]
**Topic references:**
- [Ubuntu 26.04 LTS release notes](https://documentation.ubuntu.com/release-notes/26.04/)
- [bash Reference Manual](https://www.gnu.org/software/bash/manual/)
- [ble.sh](https://github.com/akinomyoga/ble.sh)
- [Git Cheat Sheet](https://git-scm.com/cheat-sheet)
- [Claude Code Tips](https://code.claude.com/docs/en/best-practices)
- [CLAUDE.md Templates](https://code.claude.com/docs/en/memory)