Billy Kubuntu Setup
Hardware: Lenovo ThinkPad X1 2-in-1 Gen 9, Intel Core Ultra 7 155U, 16GB RAM, 512GB SSD
Scope: Full CCO (Claude Code + Obsidian with ~/Files as vault root)
Timezone: Australia/Adelaide (local)
Backup: Obsidian Sync ($4/month)
Remote support: None initially (can add Tailscale later if needed)
Encryption: Yes (LUKS) - enter passphrase each boot
Pre-Setup Checklist
- Kubuntu 25.10 USB installer (get from https://kubuntu.org/getkubuntu/)
- Verify ISO with Claude Code on Windows: ask it to verify sha256sum matches website
- 1Password account (or create one during setup)
Phase 1: OS Installation
BIOS Setup
- Boot to BIOS (F2 or F12 on ThinkPads)
- Disable Secure Boot
- Set USB as first boot device
- Save and exit
Install Kubuntu
- Boot from USB โ “Install Kubuntu”
- Language: English (Australia)
- Keyboard: US (or your preference)
- Select “Normal installation”
- Enable “Download updates while installing”
- Enable “Install third-party software”
- Partitioning: “Erase disk and install Kubuntu”
- Check “Encrypt the new Kubuntu installation” โ set strong passphrase (4+ random words or 16+ characters)
- Critical: Store this passphrase in 1Password BEFORE rebooting. If you forget it, your data is permanently unrecoverable.
- This passphrase is entered at every boot, before the login screen appears.
- Timezone: Australia/Adelaide
- Create user account (lowercase username, no spaces)
- Wait ~15-20 min
- Reboot, remove USB
First Boot
- Connect to WiFi (click network icon in system tray)
- If WiFi networks don’t appear, connect via USB ethernet adapter or phone USB tethering, then ask Claude Code to troubleshoot WiFi after Phase 3
- Open Konsole (terminal): click the application launcher (bottom-left or press Meta/Windows key) and type “Konsole”
- Run:
sudo apt update && sudo apt full-upgrade -y
- Reboot if you see “linux-image” in the upgrade list
Phase 2: Core System Setup
Remove Snap
Snap is Ubuntu’s app packaging system. We use Flatpak instead (better sandboxing, less bloat).
# Remove all snaps (may take a few attempts as dependencies resolve)
while snap list 2>/dev/null | grep -v "^Name" | grep -q .; do
snap list | tail -n +2 | awk '{print $1}' | xargs -I {} sudo snap remove --purge {} 2>/dev/null
done
# Remove snapd itself and prevent reinstall
sudo apt remove --purge snapd -y
sudo apt-mark hold snapd
# Clean up leftover directories
rm -rf ~/snap
sudo rm -rf /var/snap /var/lib/snapd
Install Core Packages
# Essential CLI tools
sudo apt install -y git curl wget build-essential htop neovim \
flatpak plasma-discover-backend-flatpak
# Add Flathub (the main Flatpak app repository)
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
Flatpak is an app packaging system (like Snap but better). Flathub is where Flatpak apps are downloaded from.
Install GUI Apps
flatpak install -y flathub com.brave.Browser
flatpak install -y flathub org.mozilla.firefox
flatpak install -y flathub md.obsidian.Obsidian
# 1Password - NOT on Flathub, uses its own repo
flatpak install -y https://downloads.1password.com/linux/flatpak/1Password.flatpakref
Install Node.js & Claude Code
# Node.js 22.x LTS
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
# Claude Code
sudo npm install -g @anthropic-ai/claude-code
# Verify installation
node --version # Should show v22.x.x
claude --version # Should show version number
WezTerm Terminal (Optional)
GPU-accelerated terminal with better font rendering than Konsole.
# Add WezTerm apt repository
sudo mkdir -p /usr/share/keyrings
curl -fsSL https://apt.fury.io/wez/gpg.key | sudo gpg --yes --dearmor -o /usr/share/keyrings/wezterm-fury.gpg
sudo chmod 644 /usr/share/keyrings/wezterm-fury.gpg
echo 'deb [signed-by=/usr/share/keyrings/wezterm-fury.gpg] https://apt.fury.io/wez/ * *' | sudo tee /etc/apt/sources.list.d/wezterm.list
# Install WezTerm and font
sudo apt update && sudo apt install -y wezterm fonts-jetbrains-mono
# Configure WezTerm
mkdir -p ~/.config/wezterm
cat > ~/.config/wezterm/wezterm.lua << 'EOF'
local wezterm = require 'wezterm'
local config = {}
config.color_scheme = 'Catppuccin Mocha'
config.font = wezterm.font 'JetBrains Mono'
config.font_size = 12.0
config.scrollback_lines = 10000
config.enable_scroll_bar = false
-- Browser-like keybindings
config.keys = {
{ key = 't', mods = 'CTRL', action = wezterm.action.SpawnTab 'CurrentPaneDomain' },
{ key = 'w', mods = 'CTRL', action = wezterm.action.CloseCurrentTab { confirm = true } },
}
-- Tab switching with Ctrl+1-9
for i = 1, 9 do
table.insert(config.keys, { key = tostring(i), mods = 'CTRL', action = wezterm.action.ActivateTab(i - 1) })
end
return config
EOF
If the apt repository fails (401 error), download the .deb from https://github.com/wezterm/wezterm/releases instead.
Hardware Check
Test a reboot now. Normal shutdown takes under 30 seconds. If it hangs for several minutes, note the issue - we’ll fix it with Claude Code in Phase 3.
Phase 3: Claude Code + Obsidian Setup
Clone Template
The template contains:
- NIPARAS folder structure: Now (today’s focus), Inbox (unsorted captures), Projects (time-bound goals), Areas (ongoing responsibilities), Resources (reference material), Archive (completed/inactive), System (configuration)
- Claude Code commands:
/parksaves session context,/pickupresumes where you left off,/morningand/goodnightfor daily routines
git clone https://github.com/OpenCairn/OpenCairn.git ~/Files
cd ~/Files
git remote rename origin template
chmod +x .claude/scripts/*.sh
Verify the commands are in place:
ls ~/Files/.claude/commands/
# Should show: park.md, pickup.md, morning.md, goodnight.md, etc.
Configure Environment
cat >> ~/.bashrc << 'BASHEOF'
# CCO: vault path (required by template scripts)
export VAULT_PATH="$HOME/Files"
# CCO: launch Claude Code from vault root
alias cc='cd ~/Files && claude'
BASHEOF
source ~/.bashrc
First Claude Code Session
Before starting: Open 1Password and sign in - you’ll need access to any passwords for authentication.
cd ~/Files
claude
# Follow authentication prompts (Google, GitHub, or email)
# Success: You'll see a ">" prompt ready for input
# If auth fails: try "claude logout" then "claude" again
Once authenticated, prompt Claude Code:
“I just set up this laptop with the CCO template. My vault is at ~/Files. Help me:
- Remap my XDG directories (Downloads, Documents, etc.) to use the NIPARAS folders in ~/Files
- Configure Dolphin file manager sidebar with the NIPARAS folders in ~/Files
- Set WezTerm as my default terminal (if I installed it)
- Fix any Bluetooth shutdown hang issues from Phase 2
- Customise CLAUDE.md with my personal context”
Claude Code will handle the system configuration and walk you through personalising your setup interactively.
Phase 4: Obsidian Sync Setup
Open Obsidian
Open vault at
~/FilesSettings โ Sync โ Subscribe ($4/month)
Create remote vault with E2E encryption password (store in 1Password!)
Critical exclusions (Settings โ Sync โ Excluded folders):
.git.claude
On your phone: Install Obsidian โ Connect to same remote vault
Restic + Backblaze B2 (Optional)
Versioned offsite backup in addition to Obsidian Sync. Costs ~$6 USD/month.
Setup steps:
- Create Backblaze B2 account at https://www.backblaze.com/b2/
- Create a bucket and application key
- Ask Claude Code: “Help me set up restic backup to Backblaze B2” - it will create the config files and systemd timer for automated daily backups
Or do it manually:
Security note: The credentials file below contains your B2 API key and backup encryption password in plaintext. Keep these values in 1Password as the authoritative source - the file is just for automation.
# Install restic
sudo apt install -y restic
# Create config directory
mkdir -p ~/.config/restic
# Create credentials file (fill in your B2 details)
cat > ~/.config/restic/env << 'EOF'
export B2_ACCOUNT_ID="your-key-id"
export B2_ACCOUNT_KEY="your-application-key"
export RESTIC_REPOSITORY="b2:your-bucket-name:backups"
export RESTIC_PASSWORD="your-restic-password"
EOF
chmod 600 ~/.config/restic/env
# Create exclusions file
cat > ~/.config/restic/excludes.txt << 'EOF'
.cache
.local/share/Trash
.npm
.nvm
.gnupg
.pki
.mozilla
.ssh
node_modules
*.log
Cache
.var
EOF
# Create backup script with error handling
cat > ~/.config/restic/backup.sh << 'EOF'
#!/bin/bash
set -e
source ~/.config/restic/env
restic backup ~ --exclude-file="$HOME/.config/restic/excludes.txt" || exit 1
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
EOF
chmod +x ~/.config/restic/backup.sh
# Initialise repo (first time only)
source ~/.config/restic/env
restic init
# Test backup
~/.config/restic/backup.sh
Phase 5: Auto-Maintenance
Flatpak Auto-Updates
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/flatpak-update.service << 'EOF'
[Unit]
Description=Update Flatpak apps
[Service]
Type=oneshot
ExecStart=/usr/bin/flatpak update -y --noninteractive
EOF
cat > ~/.config/systemd/user/flatpak-update.timer << 'EOF'
[Unit]
Description=Daily Flatpak update
[Timer]
OnCalendar=*-*-* 20:00:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now flatpak-update.timer
APT Auto-Updates
sudo tee /etc/systemd/system/apt-full-upgrade.service << 'EOF'
[Unit]
Description=APT full upgrade
[Service]
Type=oneshot
ExecStart=/usr/bin/apt update
ExecStart=/usr/bin/apt full-upgrade -y
EOF
sudo tee /etc/systemd/system/apt-full-upgrade.timer << 'EOF'
[Unit]
Description=Daily APT upgrade
[Timer]
OnCalendar=*-*-* 20:00:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now apt-full-upgrade.timer
Autotrash
# Install pipx and autotrash
sudo apt install -y pipx
pipx ensurepath
export PATH="$PATH:$HOME/.local/bin" # Make pipx available immediately
pipx install autotrash
# Install systemd timer (auto-deletes files in trash older than 10 days)
autotrash --install -d 10
Phase 6: Verification
System
- Reboot - system shuts down cleanly (no hang)
- WiFi reconnects after reboot
- Disk encryption passphrase works
Apps
- Brave opens and browses
- Obsidian opens vault at
~/Files - Claude Code starts with
cccommand - 1Password unlocks
Workflow
- Claude Code commands work - try
/park - Obsidian Sync working - changes appear on phone
Git Config (Optional)
Only needed if you’ll use git for your own projects. The template clone doesn’t require it.
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
If You Get Stuck
- Ask Claude Code - it can troubleshoot most Linux issues
- Message Harrison - can set up Tailscale for remote SSH support if needed