Thank you for your interest in contributing to Kodra! This guide covers everything you need to know to contribute effectively.
- Getting Started
- Architecture Overview
- Development Setup
- Code Standards
- Key Systems
- Adding Features
- Testing
- Pull Request Guidelines
Kodra is a developer environment for Ubuntu that transforms a vanilla install into a beautiful, productive workspace. It focuses on Azure cloud development, Docker/Kubernetes workflows, and a premium terminal experience.
- Ubuntu 24.04+ (or a container/VM for testing)
- Git
- Basic shell scripting knowledge
# Clone the repository
git clone https://github.com/codetocloudorg/kodra.git
cd kodra
# Test in a container (safe, no system changes)
docker run -it --rm -v $(pwd):/kodra ubuntu:24.04 bash
# Inside container: cd /kodra && bash install.sh --debugkodra/
├── bin/
│ ├── kodra # Main CLI dispatcher
│ ├── kodra-user-init # Per-user initialization (system-wide installs)
│ └── kodra-sub/ # Subcommand scripts (one per command)
├── configs/
│ ├── shell/ # Shell integration (aliases, functions, MOTD)
│ ├── ghostty/ # Terminal config (referenced by defaults/)
│ ├── tmux/ # Tmux configuration
│ └── btop/ # System monitor themes
├── defaults/
│ ├── ghostty/ # Base Ghostty config (Layer 1)
│ ├── shell/ # Shell config documentation
│ ├── tmux/ # Base tmux config
│ └── starship/ # Base Starship prompt config
├── install/
│ ├── kodra-base.packages # Declarative apt package list
│ ├── kodra-brew.packages # Declarative Homebrew package list
│ ├── kodra-flatpak.packages # Optional Flatpak apps
│ ├── system-wide.sh # Multi-user system-wide installer
│ ├── required/ # Core installations (always run)
│ ├── desktop/ # GNOME desktop setup
│ └── terminal/ # Terminal tools (Ghostty, Starship, etc.)
├── lib/
│ ├── utils.sh # Core utilities (logging, checks)
│ ├── ui.sh # TUI components (progress, spinners)
│ ├── logging.sh # Structured logging system
│ ├── config.sh # Config layering engine
│ ├── package.sh # Package management helpers
│ ├── state.sh # Installation state tracking
│ └── backup.sh # Backup utilities
├── migrations/
│ └── YYYYMMDDHHMMSS.sh # Timestamped upgrade scripts
├── themes/
│ └── <theme-name>/ # Theme packages (colors + configs)
├── applications/ # Optional application installers
├── wallpapers/ # Theme wallpapers
├── tests/ # Test scripts
├── boot.sh # Remote bootstrap (curl installer)
└── install.sh # Main installation orchestrator
- Idempotent — Every script can run multiple times safely
- Non-destructive — Updates never overwrite user customizations
- Resilient — Failures are logged and recoverable; install continues
- Multi-user — System-wide install at
/opt/kodra, per-user config at~/.config/kodra/ - Declarative — Package lists in manifest files, not buried in scripts
- Layered configs — Defaults → Theme → User overrides
Kodra uses a three-layer configuration system:
┌─────────────────────────────┐
│ Layer 3: User Overrides │ ~/.config/kodra/<app>/
│ (Never touched by Kodra) │
├─────────────────────────────┤
│ Layer 2: Theme │ themes/<name>/<app>.conf
│ (Applied by kodra theme) │
├─────────────────────────────┤
│ Layer 1: Defaults │ defaults/<app>/config
│ (Managed by Kodra) │
└─────────────────────────────┘
Updates only change Layer 1. Themes override Layer 1. User configs override everything.
System-wide (/opt/kodra) Per-user (~/.config/kodra/)
┌────────────────────────┐ ┌──────────────────────────┐
│ bin/kodra │ │ theme (preference file) │
│ lib/ (shared libs) │ │ shell/ (custom aliases) │
│ defaults/ (base cfg) │ │ ghostty/ (user tweaks) │
│ themes/ (all themes) │ │ migrations/ (state) │
│ install/ (scripts) │ │ initialized (marker) │
└────────────────────────┘ └──────────────────────────┘
↓ ↓
Available to ALL users Personal to each user
via /etc/profile.d/ Created by `kodra setup`
# Clone and work locally
git clone https://github.com/codetocloudorg/kodra.git ~/.kodra
cd ~/.kodra
# Set KODRA_DIR to your dev copy
export KODRA_DIR="$HOME/.kodra"
# Test a specific script
bash bin/kodra-sub/doctor.sh
# Test the theme system
bash bin/kodra-sub/theme.sh tokyo-night# Full integration test
docker run -it --rm \
-v $(pwd):/root/.kodra \
-e KODRA_DIR=/root/.kodra \
ubuntu:24.04 \
bash -c "cd /root/.kodra && bash install.sh --debug --skip-desktop"
# Quick script test
docker run -it --rm \
-v $(pwd):/root/.kodra \
ubuntu:24.04 \
bash -c "source /root/.kodra/lib/utils.sh && check_ubuntu_version"All scripts MUST:
#!/usr/bin/env bash
#
# Script Name - Brief description
# Longer description if needed
#
set -e # Exit on error (unless --debug mode)
KODRA_DIR="${KODRA_DIR:-$HOME/.kodra}"
source "$KODRA_DIR/lib/utils.sh"| Type | Convention | Example |
|---|---|---|
| Script files | lowercase-kebab.sh | night-light.sh |
| Functions | snake_case | show_help() |
| Local variables | lowercase | local theme_name |
| Global/exported | UPPERCASE | KODRA_DIR |
| Constants | UPPERCASE | VERSION |
- Always use
--max-timeoncurl/wgetcalls (10s for APIs, 30s for downloads, 60s for large files) - Never pipe curl to bash — download, verify, then execute
- Never use
evalwith user-supplied strings — usebash -cwith timeout - Never use
git reset --hardfor updates — use merge or rebase - Use marker blocks for shell config modifications (idempotent)
- Use
command -vnotwhichfor portability - Always quote variables —
"$var"not$var - Use
localfor function variables - Add
|| trueonly when you genuinely expect failures (not to silence bugs) - Test display availability with proper grouping:
{ [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; }
When modifying .bashrc/.zshrc, use the idempotent marker pattern:
# >>> kodra initialize >>>
# !! Contents within this block are managed by Kodra. Do not edit. !!
[ -f "/opt/kodra/configs/shell/kodra.sh" ] && source "/opt/kodra/configs/shell/kodra.sh"
# <<< kodra initialize <<<The _kodra_update_shell_config() helper in lib/utils.sh manages these blocks automatically.
- POSIX-overriding aliases (
cat,ls) are enabled by default but opt-out viaKODRA_POSIX_ALIASES=false - The
find→fdalias is disabled by default (breaks scripts) — opt-in viaKODRA_ALIAS_FIND=true - All aliases are conditional on the tool being installed (
command -v)
Migrations handle breaking changes between Kodra versions. They run once and are tracked via state files.
# Name format: YYYYMMDDHHMMSS.sh (UTC timestamp)
touch migrations/$(date -u +%Y%m%d%H%M%S).sh
chmod +x migrations/$(date -u +%Y%m%d%H%M%S).sh#!/usr/bin/env bash
#
# Migration: Brief description of what this does
# Date: YYYY-MM-DD
# Description: Detailed explanation of why this migration exists
#
# Your migration logic here
# - Migrations MUST be idempotent
# - Migrations run as the current user (not root)
# - Use sudo only when absolutely necessary
# - Always handle the case where the migration is not applicable
echo "Migration complete: brief description"kodra migrate # Run all pending migrations
kodra migrate status # Show migration status
kodra migrate list # List pending migrationsState is tracked at ~/.config/kodra/migrations/<name>.done (touch files).
The lib/logging.sh library provides:
source "$KODRA_DIR/lib/logging.sh"
start_install_log # Initialize logging session
run_logged "path/to/script.sh" # Run script with full logging
log_to_file "message" # Append to log
show_log_tail 20 # Display last 20 lines
stop_install_log # Finalize and save permanent logLogs are saved to ~/.config/kodra/logs/ (last 10 retained).
Packages are declared in manifest files:
install/kodra-base.packages— apt packagesinstall/kodra-brew.packages— Homebrew packagesinstall/kodra-flatpak.packages— Optional Flatpak apps
Format: one package per line, # for comments, blank lines ignored.
To read a manifest programmatically:
mapfile -t packages < <(grep -v '^#' "$KODRA_DIR/install/kodra-base.packages" | grep -v '^$')
sudo apt-get install -y "${packages[@]}"The installer uses ERR/EXIT traps that:
- Show the failed command and script
- Display log tail for context
- Offer interactive recovery (retry, view log, upload for support)
- Clean up resources (sudo keepalive, screen lock)
- Create directory:
themes/<theme-name>/ - Required files:
ghostty.conf— Terminal colors (Ghostty format)starship.toml— Prompt themevscode-settings.json— VS Code colors
- Optional files:
tmux.conf— Tmux status bar themebtop.theme— btop color scheme
- Optional: Add wallpapers to
wallpapers/<theme-name>/ - Update
bin/kodra-sub/theme.shmappings if needed
- Create script:
bin/kodra-sub/<command>.sh - Make executable:
chmod +x bin/kodra-sub/<command>.sh - Add case in
bin/kodradispatcher - Add to
show_help()inbin/kodra - Document in
docs/CHEATSHEET.md
Add to the appropriate manifest file:
- System tool →
install/kodra-base.packages - Modern CLI tool →
install/kodra-brew.packages - Desktop app →
install/kodra-flatpak.packages
When making a change that requires action on existing installs:
# Generate timestamp
TIMESTAMP=$(date -u +%Y%m%d%H%M%S)
touch "migrations/${TIMESTAMP}.sh"
chmod +x "migrations/${TIMESTAMP}.sh"
# Edit the migration script# Syntax check all scripts
find . -name "*.sh" -exec bash -n {} \;
# Run the doctor
bash bin/kodra-sub/doctor.sh
# Run basic tests
bash tests/test.sh# Full integration test (headless)
docker run -it --rm \
-v $(pwd):/root/.kodra \
-e KODRA_DIR=/root/.kodra \
-e DEBIAN_FRONTEND=noninteractive \
ubuntu:24.04 \
bash -c "apt-get update && apt-get install -y sudo curl git && \
cd /root/.kodra && bash install.sh --debug --skip-desktop"
# Test system-wide install
docker run -it --rm \
-v $(pwd):/tmp/kodra-source \
ubuntu:24.04 \
bash -c "apt-get update && apt-get install -y sudo curl git && \
cp -a /tmp/kodra-source /root/.kodra && \
export KODRA_DIR=/root/.kodra && \
sudo bash /root/.kodra/install/system-wide.sh && \
kodra doctor"
# Test migrations
docker run -it --rm \
-v $(pwd):/root/.kodra \
-e KODRA_DIR=/root/.kodra \
ubuntu:24.04 \
bash -c "source /root/.kodra/lib/utils.sh && \
bash /root/.kodra/bin/kodra-sub/migrate.sh status"Before submitting a PR:
- All scripts pass
bash -nsyntax check - Scripts are idempotent (can run multiple times)
- Network operations have timeouts
- No
curl | bashpatterns - No
evalwith dynamic content - No
git reset --hard - Shell config changes use marker blocks
- New packages added to manifest files
- Works in container (headless, no DISPLAY)
- Breaking changes have an accompanying migration
Use conventional commits:
feat: add support for custom fonts
fix: resolve theme switching on Wayland
docs: update contributing guide
refactor: migrate to marker-based shell integration
- Branch from
main - Descriptive PR title
- Tests pass in container
- No breaking changes without migration
- Documentation updated if applicable
- Scripts pass shellcheck (if available)
PRs are evaluated on:
- Safety — Does it handle errors? Does it have timeouts?
- Idempotency — Can it run multiple times without side effects?
- Non-destructiveness — Does it respect user customizations?
- Portability — Does it work on Ubuntu 24.04+?
- Clarity — Is the code readable without excessive comments?
Kodra uses semantic versioning (MAJOR.MINOR.PATCH):
- MAJOR: Breaking changes that require user action
- MINOR: New features, new themes, new commands
- PATCH: Bug fixes, security patches, documentation
The version is stored in the VERSION file at the repository root.
- Issues: https://github.com/codetocloudorg/kodra/issues
- Discussions: https://github.com/codetocloudorg/kodra/discussions
- Website: https://kodra.codetocloud.io
Thank you for making Kodra better! Every contribution helps developers have a more beautiful and productive environment. ✨