Skip to content

Commit 94b9124

Browse files
committed
Merged main
2 parents 4e65ee0 + 7a9bf9d commit 94b9124

36 files changed

Lines changed: 274 additions & 1605 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ podman_scp.*
1616
# VM testing
1717
_vm_build/
1818
.vm/
19+
.cache
1920

2021
# ISO files
2122
*.iso

AGENTS.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# AGENTS.md
2+
3+
This file provides guidance to coding agents when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Hypercube is a container-based Linux distribution built on Fedora Atomic (via Universal Blue's `base-main:43`). It's a keyboard-first Hyprland desktop with vim keybindings, Tokyo Night theming, and developer tooling. The image is built as an OCI container and deployed via bootc.
8+
9+
## Build Commands
10+
11+
```bash
12+
just build # Build container image locally (rootless Podman)
13+
just build-force # Build without cache
14+
just build-ghcr # Build for GHCR push (rootful)
15+
just run # Run container interactively for testing
16+
just lint # Shellcheck all .sh files
17+
just format # Format all .sh files with shfmt
18+
just check # Validate Justfile syntax
19+
just fix # Fix Justfile formatting
20+
```
21+
22+
### VM/ISO Testing
23+
24+
```bash
25+
just build-qcow2-fast # Create disk image via bootc install
26+
just run-qcow2 # Test qcow2 in VM with virt-manager
27+
just build-iso-local # Build ISO from local image
28+
just run-iso <file> # Test ISO in QEMU VM
29+
```
30+
31+
### Package Version Scripts
32+
33+
```bash
34+
./scripts/packages/check-upstream-versions.sh # Detect upstream updates
35+
./scripts/packages/check-copr-versions.sh # Compare spec vs COPR builds
36+
./scripts/packages/test-all.sh # Run package script tests
37+
```
38+
39+
## Architecture
40+
41+
### Build Pipeline
42+
43+
The `Containerfile` defines a multi-stage build:
44+
45+
1. **Stage `ctx`**: Aggregates `system_files/` and `build_files/` into `/ctx`
46+
2. **Main stage**: Builds from `ghcr.io/ublue-os/base-main:43`, mounts `dot_files/` at `/dot_files`, runs `build.sh`
47+
48+
`build_files/shared/build.sh` orchestrates the build:
49+
50+
- Rsyncs `system_files/shared/` to the root filesystem
51+
- Executes numbered scripts (`00-*.sh` through `99-*.sh`) sequentially from each phase directory
52+
53+
### Build Phases (in order)
54+
55+
| Directory | Purpose |
56+
| ------------------------ | ----------------------------------------------------- |
57+
| `build_files/base/` | Kernel, greetd, audio, networking, portals |
58+
| `build_files/hyprland/` | Compositor, shell, terminal, editor, CLI tools |
59+
| `build_files/dx/` | Language servers, containers (Distrobox/Podman) |
60+
| `build_files/apps/` | Applications (Steam, etc.) |
61+
| `build_files/hypercube/` | Branding, packages, theming, config deployment, tests |
62+
63+
### Configuration System
64+
65+
Configs follow XDG Base Directory specification:
66+
67+
- `dot_files/` → deployed to `/usr/share/hypercube/config/` (system defaults)
68+
- `/usr/lib/environment.d/60-hypercube-xdg.conf` adds this path to `XDG_CONFIG_DIRS`
69+
- Users override via `~/.config/`
70+
- Fish shell configs go to `/etc/fish/` (Fish doesn't use XDG_CONFIG_DIRS)
71+
- System-level files in `system_files/shared/` mirror the target filesystem path (e.g., `system_files/shared/etc/greetd/config.toml``/etc/greetd/config.toml`)
72+
73+
### Build Validation
74+
75+
`build_files/hypercube/99-tests.sh` validates the build by checking:
76+
77+
- Required packages are installed (greetd, hyprland, ghostty, neovim, etc.)
78+
- Required files exist (branding, configs, themes, plymouth)
79+
- os-release contains `ID=hypercube`
80+
- Required services are enabled (greetd, NetworkManager)
81+
82+
Failures exit with code 1, preventing the image from being published.
83+
84+
### COPR Packages
85+
86+
26 custom packages are maintained in `packages/` with RPM spec files. Package metadata, dependencies, and build ordering are defined in `scripts/packages/config.sh`. Packages are built in 5 dependency-ordered batches.
87+
88+
## Shell Script Conventions
89+
90+
- All build scripts use `set -ouex pipefail`
91+
- Scripts are named with numeric prefixes for execution ordering
92+
- Package installation uses `dnf5 -y install`
93+
- COPR repos are enabled with `dnf5 -y copr enable owner/repo`
94+
95+
## Key Integration Points
96+
97+
- **Titanoboa** (`_titanoboa/`): External ISO builder, cloned on demand by `just build-iso-*`
98+
- **Cosign** (`cosign.pub`): Image signature verification
99+
- **GitHub Actions** (`.github/workflows/build.yml`): Builds on PR and daily, pushes to GHCR on merge to main

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
| Package | Status |
5050
|---------|--------|
5151
| quickshell | [![quickshell](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/quickshell/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/quickshell/) |
52-
| regreet | [![regreet](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/regreet/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/regreet/) |
5352
| livesys-scripts | [![livesys-scripts](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/livesys-scripts/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/livesys-scripts/) |
5453

5554
</details>
@@ -90,7 +89,7 @@ Tokyo Night color scheme everywhere:
9089
- Terminal emulators
9190
- Neovim and all CLI tools
9291
- Plymouth boot animation
93-
- ReGreet login screen
92+
- Hypercube greeter
9493
- System-wide dark mode enforced
9594

9695
## Screenshots

build_files/apps/01-apps.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,18 @@ echo "Installing applications..."
99
### Web Browser
1010
dnf5 -y install firefox
1111

12+
### Flatpak Applications (system-wide, baked into image)
13+
flatpak remote-add --if-not-exists --system flathub https://flathub.org/repo/flathub.flatpakrepo
14+
flatpak install --system --noninteractive flathub \
15+
io.github.kolunmi.Bazaar \
16+
com.usebottles.bottles \
17+
io.github.dvlv.boxbuddyrs \
18+
org.gnome.Boxes \
19+
com.github.tchx84.Flatseal \
20+
be.alexandervanhee.gradia \
21+
io.github.seadve.Kooha \
22+
io.podman_desktop.PodmanDesktop \
23+
org.mozilla.Thunderbird \
24+
io.github.flattool.Warehouse
25+
1226
echo "Applications installed successfully"

build_files/base/01-base-system.sh

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22
# Hypercube Base System
3-
# Installs core system components, display manager (greetd + regreet), and hardware support
3+
# Installs core system components, display manager (greetd + hypercube-utils), and hardware support
44

55
set -ouex pipefail
66

@@ -12,14 +12,12 @@ dnf5 -y clean all
1212
### Enable Hypercube COPR for custom packages
1313
dnf5 -y copr enable binarypie/hypercube
1414

15-
### Display Manager: greetd + regreet
16-
# regreet from binarypie/hypercube COPR
17-
# cage is a minimal Wayland compositor to host regreet and the first-boot wizard
15+
### Display Manager: greetd + hypercube-utils
16+
# hypercube-utils provides hypercube-greeter and hypercube-onboard (run directly on TTY)
1817
dnf5 -y install \
1918
greetd \
2019
greetd-selinux \
21-
cage \
22-
regreet
20+
hypercube-utils
2321

2422
### Desktop Portals & Integration
2523
dnf5 -y install \
@@ -84,7 +82,7 @@ dnf5 -y install \
8482
gvfs-gphoto2 \
8583
gvfs-smb
8684

87-
### Flatpak (ensure latest version for preinstall.d support)
85+
### Flatpak
8886
dnf5 -y install flatpak
8987

9088
### Homebrew integration (from ublue COPR)

build_files/hypercube/03-hypercube-configs.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,6 @@ install -Dm644 "${CONFIG_DIR}/gtk-4.0/settings.ini" /etc/xdg/gtk-4.0/settings.in
7878
install -Dm644 "${CONFIG_DIR}/qt6ct/qt6ct.conf" /etc/xdg/qt6ct/qt6ct.conf
7979
install -Dm644 "${CONFIG_DIR}/qt6ct/colors/TokyoNight.conf" /usr/share/qt6ct/colors/TokyoNight.conf
8080

81-
### ReGreet login greeter configuration (Tokyo Night themed)
82-
install -Dm644 "${CONFIG_DIR}/regreet/regreet.toml" /etc/greetd/regreet.toml
83-
install -Dm644 "${CONFIG_DIR}/regreet/regreet.css" /etc/greetd/regreet.css
84-
8581
### Enable xdg-desktop-portal-gtk for dark mode detection (Firefox, etc.)
8682
# This portal provides the org.freedesktop.appearance.color-scheme setting
8783
systemctl --global enable xdg-desktop-portal-gtk.service

build_files/hypercube/99-tests.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ echo "Running Hypercube validation tests..."
1010
REQUIRED_PACKAGES=(
1111
# Display manager
1212
"greetd"
13-
"regreet"
14-
"cage"
13+
"hypercube-utils"
1514
# Hyprland stack
1615
"hyprland"
1716
"hyprlock"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Hypercube Onboarding Configuration
2+
# Used by hypercube-onboard during first boot (greetd initial_session)
3+
4+
[user]
5+
# User creation settings
6+
groups = ["wheel"]
7+
shell = "/usr/bin/fish"
8+
min_password_length = 8
9+
10+
[locale]
11+
# Default locale settings
12+
language = "en_US.UTF-8"
13+
keyboard_layout = "us"
14+
15+
[timezone]
16+
# Timezone preferences
17+
use_ntp = true
18+
19+
[completion]
20+
# What to do when onboarding finishes
21+
action = "reboot"
22+
remove_initial_session = true
23+
24+
[updates]
25+
# System updates to run during onboarding
26+
27+
[[updates.commands]]
28+
description = "System update"
29+
command = "ujust update"

dot_files/hypr/hyprland-kiosk.conf

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Hyprland Kiosk Mode Configuration
2+
# Used for desktop kiosk mode applications
3+
# - No keybindings (locked down)
4+
# - Single fullscreen application
5+
# - Exits when the application closes
6+
#
7+
# Usage: Set KIOSK_CMD environment variable before launching
8+
# KIOSK_CMD="your-app" Hyprland -c /path/to/hyprland-kiosk.conf
9+
10+
################
11+
### MONITORS ###
12+
################
13+
14+
# Enable all monitors - kiosk app shows on primary, others show wallpaper
15+
monitor=,preferred,auto,auto
16+
17+
#################
18+
### AUTOSTART ###
19+
#################
20+
21+
# Wallpaper on all monitors
22+
exec-once = hyprpaper -c /usr/share/hypercube/config/hypr/hyprpaper.conf
23+
24+
# Launch the kiosk application from environment variable
25+
exec-once = $KIOSK_CMD
26+
27+
# Exit Hyprland when the last window closes
28+
exec-once = handle=$(hyprctl -j clients | jq -r '.[0].address // empty'); while [ -n "$handle" ]; do sleep 0.5; handle=$(hyprctl -j clients | jq -r '.[0].address // empty'); done; hyprctl dispatch exit
29+
30+
#############################
31+
### ENVIRONMENT VARIABLES ###
32+
#############################
33+
34+
env = XCURSOR_SIZE,24
35+
env = HYPRCURSOR_SIZE,24
36+
37+
#####################
38+
### LOOK AND FEEL ###
39+
#####################
40+
41+
general {
42+
gaps_in = 0
43+
gaps_out = 0
44+
border_size = 0
45+
col.active_border = rgba(00000000)
46+
col.inactive_border = rgba(00000000)
47+
resize_on_border = false
48+
allow_tearing = false
49+
layout = dwindle
50+
}
51+
52+
decoration {
53+
rounding = 0
54+
active_opacity = 1.0
55+
inactive_opacity = 1.0
56+
shadow {
57+
enabled = false
58+
}
59+
blur {
60+
enabled = false
61+
}
62+
}
63+
64+
animations {
65+
enabled = false
66+
}
67+
68+
dwindle {
69+
pseudotile = false
70+
preserve_split = true
71+
}
72+
73+
misc {
74+
force_default_wallpaper = 0
75+
disable_hyprland_logo = true
76+
}
77+
78+
#############
79+
### INPUT ###
80+
#############
81+
82+
input {
83+
kb_layout = us
84+
kb_variant =
85+
kb_model =
86+
kb_options =
87+
kb_rules =
88+
follow_mouse = 1
89+
sensitivity = 0
90+
touchpad {
91+
natural_scroll = false
92+
}
93+
}
94+
95+
###################
96+
### KEYBINDINGS ###
97+
###################
98+
99+
# No keybindings - kiosk mode is locked down
100+
101+
##############################
102+
### WINDOWS AND WORKSPACES ###
103+
##############################
104+
105+
# Force all windows to fullscreen
106+
windowrule = fullscreen, match:class .*
107+
windowrule = nofocus, match:class ^$, match:title ^$

dot_files/quickshell/modules/common/Config.qml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@ Singleton {
6262
launcher: {
6363
maxResults: 50,
6464
showCategories: true
65-
},
66-
system: {
67-
preinstallCompleted: false
6865
}
6966
})
7067

@@ -111,9 +108,6 @@ Singleton {
111108
property int launcherMaxResults: defaults.launcher.maxResults
112109
property bool launcherShowCategories: defaults.launcher.showCategories
113110

114-
// System settings
115-
property bool preinstallCompleted: defaults.system.preinstallCompleted
116-
117111
// Load config synchronously at startup
118112
FileView {
119113
id: configFile
@@ -204,11 +198,6 @@ Singleton {
204198
launcherShowCategories = config.launcher.showCategories ?? launcherShowCategories
205199
}
206200

207-
// System
208-
if (config.system) {
209-
preinstallCompleted = config.system.preinstallCompleted ?? preinstallCompleted
210-
}
211-
212201
console.log("Config: Loaded from", root.configPath)
213202
} catch (e) {
214203
console.error("Config: Failed to parse:", e)
@@ -277,9 +266,6 @@ Singleton {
277266
addIfChanged(config, "launcher", "maxResults", launcherMaxResults, defaults.launcher.maxResults)
278267
addIfChanged(config, "launcher", "showCategories", launcherShowCategories, defaults.launcher.showCategories)
279268

280-
// System
281-
addIfChanged(config, "system", "preinstallCompleted", preinstallCompleted, defaults.system.preinstallCompleted)
282-
283269
// Only write if there are changes
284270
if (Object.keys(config).length === 0) {
285271
console.log("Config: No changes from defaults, skipping save")

0 commit comments

Comments
 (0)