first commit

This commit is contained in:
2026-10-28 09:17:40 -06:00
commit 49360140af
48 changed files with 2861 additions and 0 deletions
+134
View File
@@ -0,0 +1,134 @@
---
title: "Home"
description: "Federated CoreDesktop turns a fresh Arch Linux and GNOME install into a tiling, keyboard-first desktop with the software you need for work, sandboxed AI agents, snapshots, backups and one-command updates."
sections:
- type: hero
eyebrow: "Not a distribution, yet. Just Arch, GNOME and some very good scripts."
title: "A tiling Arch desktop, ready for work in one command."
subhead: "CoreDesktop takes a fresh **Arch Linux + GNOME** install and turns it into a keyboard-first workstation with a flexible tiling system, with the apps, developer tools, firewall, snapshots, backups and **sandboxed AI agents** already set up."
ctas:
- label: "Install CoreDesktop"
url: "/install/"
style: primary
- label: "What's included"
url: "#included"
style: ghost
video: "/video/ultrawide-desktop"
videoTitle: "CoreDesktop · 5120 × 1440 ultrawide"
videoLabel: "A CoreDesktop screen on an ultrawide monitor: three tiled windows side by side, a zoom out to the GNOME overview with the dock, and back."
- type: text
body: "CoreDesktop is *some scripts*, not a distribution, yet. Arch Linux does the heavy lifting, so you get upstream fixes as they land, and a *flexible tiling* desktop that makes the most of any screen, *ultrawides* included."
- type: features
id: included
kicker: "What you get"
headline: "Everything set up, nothing in the way."
lede: "One install script, safe to run again. If something fails, run it again. It skips what's already done."
items:
- label: "A tiling desktop you drive from the keyboard"
body: "GNOME with the Tiling Shell extension: a flexible tiling system you can lay out however you like, Super + arrow keys to move windows, and the full mouse-friendly desktop when you want it."
- label: "The software you'd install anyway"
body: "From pacman, the AUR, Flathub and mise: browsers, messaging, office, media, notes, remote desktop, database clients and local AI, plus a full developer toolchain."
- label: "Sandboxed AI agents"
body: "opencode, Hermes Agent, Cline Desktop and Claude Code run in a sandbox that can only change your project folder and can't read your keys or passwords."
- label: "Snapshots and backups"
body: "Snapper snapshots / before every update. `configure` adds encrypted, daily restic backups of your home folder to your Nextcloud."
- label: "Safe by default"
body: "The ufw firewall is on, Docker can't punch holes in it, and [`audit`](/utilities/#audit) shows every open port and who can reach it."
- label: "One command to stay current"
body: "`update` snapshots, then updates Arch, GNOME, AUR, Flatpaks, Ruby, extensions and firmware, and tells you if a step failed."
ctas:
- label: "Browse the software"
url: "/software/"
style: text
- label: "See the system defaults"
url: "/system/"
style: text
- type: stats
kicker: "By the numbers"
headline: "A lot of setup you won't have to do."
items:
- value: "1"
label: "command to install, after Arch and GNOME"
- value: "48"
label: "Flatpak apps, from browsers to video editing"
- value: "4"
label: "AI coding agents, each in a sandbox"
- value: "20"
label: "steps that `update` runs, in order"
- type: steps
kicker: "How it works"
headline: "From USB stick to working desktop."
items:
- title: "Install Arch with GNOME"
body: "Boot the Arch ISO and run `archinstall`. Choose the desktop profile, GNOME, pipewire and the right GPU driver."
- title: "Run one command"
body: "Open a terminal, paste the install command, and enter your password once. Then be patient: it takes a while."
- title: "Configure and reboot"
body: "`configure` connects your Federated Core, joins your Tailscale network, sets up backups and signs in your AI agents."
ctas:
- label: "Read the full install guide"
url: "/install/"
style: primary
- type: command
kicker: "The install command"
headline: "Already on Arch and GNOME?"
lede: "Open a terminal and paste this in."
note: "The scripts live in `~/.local/share/coredesktop/`. Read [install.sh](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/install.sh) before you run it."
- type: cards
kicker: "Built for Federated Computer"
headline: "Even better with your Federated Core."
lede: "CoreDesktop is what the Federated Computer team works on every day. Point it at your Core and it wires itself into your apps."
columns: 3
items:
- label: "Accounts"
title: "Calendar, contacts, files and email"
body: "Your Nextcloud and email go into GNOME Online Accounts, your files mount in the Files sidebar, and Element points at your Core's Matrix server."
link: "/utilities/#configure"
linktext: "Connect your Core"
- label: "Network"
title: "Your own Tailscale network"
body: "Join this computer to your Core's headscale, so you can reach your other machines from anywhere."
link: "/utilities/#configure"
linktext: "Set up Tailscale"
- label: "Backups"
title: "Encrypted, daily, off this machine"
body: "restic backs up your home folder to your Nextcloud: 7 daily, 4 weekly and 6 monthly, with a passphrase only you keep."
link: "/utilities/#restoring-from-a-backup"
linktext: "How restoring works"
- type: faq
kicker: "Questions"
headline: "Good to know before you start."
items:
- q: "Is CoreDesktop a Linux distribution?"
a: "Not yet. Today it's a set of scripts that runs on top of a standard Arch Linux and GNOME install. Arch does the heavy lifting; CoreDesktop adds the extensions, software and configuration."
- q: "Do I need a Federated Computer account?"
a: "No. Everything except the `configure` steps for your Core, its Tailscale network and backups works on its own. A lot of the software is chosen for work at Federated Computer, but you may find it useful too."
- q: "What if the install fails halfway?"
a: "Run the command again. It skips what's already done and picks up where it stopped."
- q: "Does it work on ultrawide monitors?"
a: "That's what it's best at. The tiling system adapts to any screen: pick a layout from the tiling icon in the top-right corner, or make your own."
- q: "Can I add my own tools on top?"
a: "Yes. A sibling project is any git repository with an optional `install.sh` and `update.sh`. Install it with `sibling`, and every `update` keeps it current."
ctas:
- label: "Sibling projects"
url: "/siblings/"
style: text
- type: final-cta
headline: "Get a better desktop this afternoon."
body: "Install Arch with GNOME, paste one command, and come back to a tiling workstation that's ready for work."
ctas:
- label: "Install CoreDesktop"
url: "/install/"
style: primary
- label: "View the source"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop"
style: ghost
---
+94
View File
@@ -0,0 +1,94 @@
---
title: "AI Sandbox"
description: "Federated CoreDesktop installs opencode, Hermes Agent, Cline Desktop and Claude Code, and runs them in a sandbox that keeps them out of your keys, passwords and other files."
sections:
- type: hero
compact: true
eyebrow: "opencode · Hermes Agent · Cline Desktop · Claude Code"
title: "AI agents that can't wander off."
subhead: "CoreDesktop installs four AI coding agents and runs them in a sandbox. They can change your project, and not much else."
ctas:
- label: "Sign in your agents"
url: "/utilities/#configure"
style: primary
- label: "Sandbox rules"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/sandbox/config"
style: ghost
logTitle: "~/Projects/site $ opencode"
log:
- tag: "Sandbox"
text: "Write access: ~/Projects/site only"
- tag: "Read"
text: "Reading content/_index.md and hugo.toml"
- tag: "Write"
text: "Edited layouts/partials/header.html"
- think: true
tag: "Agent"
text: "Trying to read ~/.ssh/id_ed25519"
- tag: "Blocked"
text: "~/.ssh is hidden from the sandbox"
- tag: "Net"
text: "github.com, npm and PyPI: allowed"
- tag: "Blocked"
text: "pastebin.example: not on the allow list"
- done: true
text: "Done. 1 file changed, nothing else touched."
- type: split
kicker: "In the sandbox"
headline: "What an agent can and can't do."
columns:
- title: "It can"
items:
- "Change files only in the directory you start it from, plus its own settings and a few package caches. So start it from a project directory."
- "Reach AI providers and common developer sites: GitHub, Gitea, npm, PyPI, crates.io, RubyGems, the Go module proxy and archlinux.org."
- title: "It can't"
items:
- "Read your SSH keys, password stores or browser profiles"
- "Read Flatpak apps' data: browsers, Signal, Telegram and the rest"
- "Read your Nextcloud password, cloud and Git credentials"
- "Read the other agents' logins"
- type: cards
kicker: "The agents"
headline: "Four agents, one sandbox."
columns: 2
items:
- label: "opencode"
title: "Sandboxed when you type it"
body: "Typing `opencode` runs it in the sandbox. To run it without, type `unsandboxed opencode`."
- label: "Hermes Agent"
title: "Talk to it over Matrix"
body: "`hermes` or `hermes-agent` runs in the sandbox, and so does its gateway, which lets you talk to Hermes through Matrix and other messaging apps. Its sandbox allows local sockets but hides your D-Bus session, SSH agent, Docker, Tailscale, X11, tmux and browsers."
- label: "Cline Desktop"
title: "Your projects in ~/Projects"
body: "Opened from the app menu. It can change files in `~/Projects`, open projects elsewhere only to read them, and reach cline.bot. It draws through Wayland without the GPU, D-Bus or the keyring. `unsandboxed cline-desktop` runs it without the sandbox."
- label: "Claude Code"
title: "Its own built-in sandbox"
body: "Claude Code uses its own built-in sandbox for every command it runs. See `/sandbox` inside Claude."
- type: text
kicker: "Allow more"
headline: "When an agent needs a site or folder."
body: |
Add it in `~/.config/coredesktop/sandbox/base.json` for every agent, or in `~/.config/coredesktop/sandbox/opencode.json` (and so on) for one agent:
```
{
"network": { "allowedDomains": ["docs.example.com"] },
"filesystem": { "allowWrite": ["~/notes"] }
}
```
For Hermes' gateway to reach messaging services other than the Matrix server in its settings, add their domains the same way.
The sandbox is Anthropic's [sandbox runtime](https://github.com/anthropics/sandbox-runtime), which uses bubblewrap and socat. The default rules are in [sandbox/config/](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/sandbox/config).
- type: final-cta
headline: "Sign in and pick a model provider."
body: "Before using an agent the first time, run `configure`."
ctas:
- label: "Configure your agents"
url: "/utilities/#configure"
style: primary
---
+65
View File
@@ -0,0 +1,65 @@
---
title: "Contribute"
description: "Help make Federated CoreDesktop better: suggest software, send a pull request, and learn how changes reach existing machines through migrations."
sections:
- type: hero
compact: true
eyebrow: "MIT licensed · Pull requests welcome"
title: "Help make CoreDesktop better."
subhead: "Want to help? Awesome! We welcome any and all help. Suggest missing titles or services, or contribute a PR and we're off to a better CoreDesktop."
visual: false
ctas:
- label: "Open the repository"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop"
style: primary
- type: steps
kicker: "Ways to help"
headline: "Pick one."
items:
- title: "Suggest software"
body: "Missing a title or service you use every day? Tell us, and say why."
- title: "Send a pull request"
body: "Packages live in `packages.conf`, Flatpaks in `install-flatpaks.sh`, update steps in `updates.d/` and setup in `configure.d/`."
- title: "Build a sibling"
body: "Have something that's only for you or your team? Make it a [sibling project](/siblings/) instead."
- type: text
kicker: "Migrations"
headline: "Getting a change to existing machines."
body: |
Changes to `install.sh` only reach new installs. If existing machines need the change too, also add a migration: a script named after the current time,
```
migrations/$(date +%s).sh
```
that `update` runs once on each machine. It may also run on fresh installs, so make it safe to repeat.
- type: text
id: license
kicker: "License"
headline: "MIT, the whole project."
body: |
Copyright 2026 Federated Computer, Inc. Permission is granted, free of charge, to anyone who gets a copy of this software to use, copy, modify, merge, publish, distribute, sublicense and sell it, as long as the copyright and permission notice are included. The software is provided as is, without warranty of any kind.
Read the full text in [LiCENSE.md](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/LiCENSE.md).
- type: text
kicker: "Thanks"
headline: "Standing on good shoulders."
body: |
Most of the heavy lifting is done by [Arch Linux](https://archlinux.org), and to that distribution we send much gratitude. Arch lets us get on with building, instead of waiting for upstream changes and fixes.
These scripts are based on the initial work of [Typecraft](https://www.youtube.com/@typecraft_dev).
- type: final-cta
headline: "Ready when you are."
ctas:
- label: "Install CoreDesktop"
url: "/install/"
style: primary
- label: "View the source"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop"
style: ghost
---
+91
View File
@@ -0,0 +1,91 @@
---
title: "Install"
description: "Install Arch Linux with GNOME, then install Federated CoreDesktop with one command."
sections:
- type: hero
compact: true
eyebrow: "About an afternoon, most of it waiting"
title: "Install Arch, then CoreDesktop."
subhead: "Two parts: a standard Arch Linux install with GNOME using `archinstall`, then one command that turns it into CoreDesktop."
tiles: ["archinstall", "install.sh", "configure"]
ctas:
- label: "Skip to the command"
url: "#installing-federated-coredesktop"
style: primary
- label: "Download Arch"
url: "https://archlinux.org/download/"
style: ghost
- type: steps
kicker: "Part one"
headline: "Installing Arch."
lede: "Mostly choose the defaults. The choices below are the ones that matter."
items:
- title: "Download the ISO"
body: "Get the Arch ISO from [archlinux.org/download](https://archlinux.org/download/). You may need to scroll down to find the download links."
- title: "Write it to a USB stick"
body: "Any tool works. On another CoreDesktop machine, use Impression."
- title: "Boot it and run archinstall"
body: "Boot from the USB stick. When it's up, type `archinstall` to get to the simple installer. No wired connection? [Set up wifi first](#a-note-about-networking-in-arch)."
- title: "Pick the right GPU driver"
body: "**If you have an NVIDIA GPU, choose the proprietary NVIDIA option.** Choose the AMD option for AMD cards."
- title: "Choose desktop and GNOME"
body: "When asked what type of system you want, choose **Desktop**, and **GNOME** as the desktop environment."
- title: "Choose pipewire, then reboot"
body: "Pipewire is strongly recommended for sound; it works well with Jitsi, Element and the other Federated Core apps. Reboot and log in."
- type: callout
text: "You will likely get the Arch install wrong the first or second time. Don't despair. Keep trying! The logic of the install will become clear, and frankly efficient, and you get to know the base Arch install better each time."
- type: text
id: a-note-about-networking-in-arch
kicker: "Networking"
headline: "A note about networking in Arch."
body: |
You need an internet connection to install Arch. A wired connection should just work. On wifi, set it up with `iwctl` before running `archinstall`:
```
iwctl
device list
station wlan0 scan
station wlan0 get-networks
station wlan0 connect SSID
```
Replace `wlan0` with your wireless device from `device list`, and `SSID` with your network's name. Leave `iwctl` and check with `ping archlinux.org`, then carry on with the install. The Arch wiki has [the full guide](https://wiki.archlinux.org/title/Network_configuration/Wireless).
- type: command
id: installing-federated-coredesktop
kicker: "Part two"
headline: "Installing Federated CoreDesktop."
lede: "Once Arch and GNOME are installed, log in, open a terminal and enter:"
note: "You can also find this command on [Gitea](https://gitea.federated.computer/Federated_Computer/coredesktop): open the Web browser, go to gitea.federated.computer, click Explore, then CoreDesktop."
- type: steps
kicker: "Then"
headline: "While it runs, and after."
items:
- title: "Enter your password once"
body: "It asks once, at the start. Then be patient: it takes a while."
- title: "Run configure"
body: "At the end it offers to run `configure`, which connects your Federated Core, sets up backups and signs you in to the AI agents. If a newer kernel came in, it asks you to reboot first."
- title: "If something fails, run it again"
body: "The install skips what's already done, so running it again is always safe."
- title: "Reboot"
body: "Run `sudo reboot now` when you're done, so that Element can find the encryption keychain, among other things."
ctas:
- label: "What configure sets up"
url: "/utilities/#configure"
style: primary
- label: "What gets installed"
url: "/software/"
style: text
- type: final-cta
headline: "Installing? Put this on."
body: "Here's a [nice song to listen to while you're installing](https://music.youtube.com/watch?v=y-5o2f9wzmw&si=_z9kcKHRwj-KTs7w)."
ctas:
- label: "Next: Configure"
url: "/utilities/#configure"
style: primary
---
+260
View File
@@ -0,0 +1,260 @@
---
title: "Siblings"
description: "Sibling projects are git repositories that build on Federated CoreDesktop. Install them with one command, keep them current with update, browse the directory, and learn how to format and submit your own."
sections:
- type: hero
compact: true
eyebrow: "sibling · sibling add · sibling list · sibling remove"
title: "Build your own layer on top."
subhead: "A sibling project is a git repository that builds on CoreDesktop. Install one with a single command, and every `update` keeps it current along with everything else."
ctas:
- label: "Browse siblings"
url: "#directory"
style: primary
- label: "Make your own"
url: "#format"
style: ghost
logTitle: "~ $ sibling add https://gitea.example.com/someone/my-tools.git"
log:
- tag: "Clone"
text: "my-tools into ~/.local/share/siblings/my-tools"
- tag: "install"
text: "Running install.sh from the repo folder"
- tag: "pacman"
text: "Installing jq and ripgrep"
- tag: "Bin"
text: "Installed ~/.local/bin/my-tools"
- done: true
text: "my-tools installed. update keeps it current."
- type: text
kicker: "What's a sibling?"
headline: "Your tools, updated with CoreDesktop."
body: |
CoreDesktop covers what most people need. A sibling covers the rest: your team's tools, your dotfiles, the extra apps your work depends on. It's an ordinary git repository with two optional scripts at its top level, `install.sh` and `update.sh`.
`sibling` clones the repository into `~/.local/share/siblings/` and runs its `install.sh` once. After that, every `update` pulls the latest version of each sibling and runs its `update.sh`, so the people using your project get your changes without doing anything.
A repository needs no special files to be installable. Without the scripts, `update` just keeps the clone up to date.
- type: command
id: install-a-sibling
kicker: "Install one"
headline: "One command to add a sibling."
lede: "It asks for the repository's git URL, clones it, runs its install.sh (if it has one), and confirms the install."
command: "sibling"
note: "Any URL or path `git clone` accepts will do. Private repositories work too, as long as you can already clone them (SSH key, credential helper or password), and every later `update` needs the same access."
- type: table
kicker: "Commands"
headline: "Everything sibling does."
headers: ["Command", "What it does"]
rows:
- ["`sibling`", "Asks for a git URL, then installs that project"]
- ["`sibling add <url>`", "The same, without the prompt. Run it again to repair an install"]
- ["`sibling list`", "Shows the installed siblings, their URLs and current commits"]
- ["`sibling remove <name>`", "Deletes `~/.local/share/siblings/<name>`. Anything its install.sh set up elsewhere stays"]
- type: siblings
id: directory
kicker: "Directory"
headline: "Sibling projects."
lede: "Projects that build on CoreDesktop. Copy a command into a terminal to install one."
emptyText: "**No sibling projects are listed yet.** Built something on CoreDesktop? Yours could be the first."
emptyCtas:
- label: "Submit your project"
url: "#submit"
style: primary
- label: "How to format it"
url: "#format"
style: text
- type: steps
id: format
kicker: "Make your own"
headline: "Turn a repository into a sibling."
lede: "Both scripts are optional, and both go at the top level of the repository. Other names or locations are ignored."
items:
- title: "Add install.sh"
body: "Runs once, when someone runs `sibling add`, and again if they re-run it. Use it for one-time setup: prompts, accounts, initial config."
- title: "Add update.sh"
body: "Runs on every `update`, right after the repository has been pulled. Use it to apply what changed since the last update."
- title: "Tell people how to install it"
body: "In your README, tell users to install with `sibling add <url>`. Then [submit it](#submit) to the directory."
- type: split
kicker: "The rules"
headline: "What each script should do."
lede: "Both run with `bash`, from the repository folder, so they don't need to be executable. A `#!/bin/bash` line keeps them runnable by hand."
columns:
- title: "install.sh"
items:
- "**Exit non-zero on failure.** `set -e` near the top is the simplest way. `sibling` then tells the user it failed and how to retry."
- "**Make it safe to re-run.** Re-running `sibling add` is how users repair an install, so skip work that's already done instead of failing on it."
- "It may prompt the user, since it runs in their terminal."
- "Install commands into `~/.local/bin` (already on `PATH`) with `install_script`."
- title: "update.sh"
items:
- "**Make it idempotent.** It runs on every `update`, usually with nothing to do."
- "**Don't prompt.** Users expect `update` to run through without questions, apart from `sudo` passwords."
- "**Exit non-zero only for real failures**, so that `update`'s error summary stays meaningful."
- "**Print what it's doing.** CoreDesktop prints only the project's name before it runs."
- "It's fine to leave it out if pulling the repository is enough, for example when `~/.local/bin` holds symlinks into the repo."
- type: features
kicker: "Good to know"
headline: "The environment your scripts run in."
items:
- label: "Nothing is inherited"
body: "Each script runs as its own `bash` process, with no variables or functions from CoreDesktop. `$COREDESKTOP` is not set, so set it yourself: `COREDESKTOP=\"$HOME/.local/share/coredesktop\"`."
- label: "Find your own files"
body: "Locate files relative to the script, not a hard-coded path. People may clone the repository somewhere else and run install.sh by hand."
- label: "Keep pulls working"
body: "`update` pulls with `--ff-only` and never merges or resets. Never force-push the default branch, and never write into tracked files: put generated files and per-machine state in `~/.config/<name>/` or in paths listed in `.gitignore`."
- label: "sudo works as normal"
body: "`sudo` prompts for a password as usual. CoreDesktop doesn't give siblings passwordless sudo."
- type: table
kicker: "Helpers"
headline: "CoreDesktop's helpers, from utils.sh."
lede: "Source `$COREDESKTOP/utils.sh` to use them."
headers: ["Function", "What it does"]
rows:
- ["`install_packages ...`", "Installs pacman and AUR packages with yay, skipping installed ones"]
- ["`remove_packages ...`", "Removes installed pacman and AUR packages"]
- ["`remove_flatpaks ...`", "Uninstalls Flatpaks that are installed"]
- ["`enable_services ...`", "Enables systemd services not yet enabled"]
- ["`install_script src dst`", "Copies a file atomically and makes it executable"]
- ["`is_installed pkg`", "True if a pacman package is installed"]
- type: text
id: templates
kicker: "Templates"
headline: "Start from these."
body: |
Share the install logic between the two scripts, so packages or commands you add later reach existing machines through `update`, not just new installs.
**install.sh**
```
#!/bin/bash
#
# Purpose : Install <project> (run by CoreDesktop's `sibling add`)
set -e
SELF="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COREDESKTOP="$HOME/.local/share/coredesktop"
source "$COREDESKTOP/utils.sh"
# One-time setup: prompts, accounts, initial config...
mkdir -p "$HOME/.config/<project>"
# Everything that update.sh also needs to keep current
bash "$SELF/update.sh"
echo "<project> installed."
```
**update.sh**
```
#!/bin/bash
#
# Purpose : Keep <project> current (run by CoreDesktop's `update`)
set -e
SELF="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COREDESKTOP="$HOME/.local/share/coredesktop"
source "$COREDESKTOP/utils.sh"
PACKAGES=(
jq
ripgrep
)
install_packages "${PACKAGES[@]}"
mkdir -p "$HOME/.local/bin"
install_script "$SELF/bin/<project>" "$HOME/.local/bin/<project>"
```
- type: text
id: testing
kicker: "Testing"
headline: "Try it in a throwaway home folder."
body: |
Point `sibling` at a local clone, with a temporary `HOME` so nothing touches your real one:
```
export HOME="$(mktemp -d)"
mkdir -p "$HOME/.local/share"
ln -s /path/to/real/coredesktop "$HOME/.local/share/coredesktop"
# Install
bash "$HOME/.local/share/coredesktop/sibling" add /path/to/sibling-repo
# Commit a change in /path/to/sibling-repo, then run the update hook the way update does
( source "$HOME/.local/share/coredesktop/updates.d/71-siblings.sh"; is_installed && run_update )
# Re-run the install to check it's safe to repeat
bash "$HOME/.local/share/coredesktop/sibling" add /path/to/sibling-repo
```
Scripts that call `sudo`, `yay` or `systemctl` still change the real system, even with a temporary `HOME`. Test those on a machine or VM you don't mind changing.
- type: text
id: custom-hooks
kicker: "Advanced"
headline: "Full control with an update hook."
body: |
Instead of `update.sh`, a project can install its own hook into CoreDesktop's `updates.d/`, which `update` runs in filename order. Use one approach or the other, not both, or the project updates twice.
Name the hook with an unused number from **72 to 79**, so it runs after CoreDesktop's own updates but before its end-of-run steps (80 and up), and copy it in from your install.sh:
```
cp updates.d/72-myproject.sh ~/.local/share/coredesktop/updates.d/
```
A hook can define `run_update`, and optionally `is_installed`, so it's skipped on machines where the project isn't installed. The full guide is in [sibling-project-updates.md](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/skills/sibling-project-updates.md).
- type: checklist
kicker: "Checklist"
headline: "Before you share it."
items:
- "The repository can be cloned by URL by the people who will install it."
- "`install.sh` (optional) is at the top level, exits non-zero on failure, and is safe to re-run."
- "`update.sh` (optional) is at the top level, idempotent, doesn't prompt, and prints what it's doing."
- "Scripts find their own files relative to the script and set `COREDESKTOP=\"$HOME/.local/share/coredesktop\"` themselves."
- "Nothing writes to tracked files in the clone, and the default branch is never force-pushed."
- "The project doesn't also copy a hook into CoreDesktop's `updates.d/`."
- "The README tells users to install with `sibling add <url>`."
- type: steps
id: submit
kicker: "Submit"
headline: "Get your project in the directory."
lede: "Built a sibling other people could use? Tell us about it, and we'll add it to the directory."
items:
- title: "Check it"
body: "Go through the [checklist](#checklist). The repository must be public, so anyone can install it with `sibling add`, and should have a license."
- title: "Open an issue"
body: "Open an issue on the CoreDesktop repository titled **Sibling: your project's name**, with its git URL, a one-line description, and your name or handle."
- title: "We'll take a look"
body: "We'll install it on a test machine, and once it works, add it to the directory. We'll reply on the issue either way."
ctas:
- label: "Submit a sibling"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop/issues/new"
style: primary
- label: "Read the full format guide"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/skills/sibling-project-format.md"
style: text
- type: final-cta
headline: "Need CoreDesktop itself changed?"
body: "If what you're building would be useful to everyone, it might belong in CoreDesktop instead of a sibling."
ctas:
- label: "Contribute to CoreDesktop"
url: "/contribute/"
style: primary
---
+104
View File
@@ -0,0 +1,104 @@
---
title: "Software"
description: "What Federated CoreDesktop installs: pacman packages, AUR packages, 48 Flatpaks, Ruby and Rails with mise, and a full set of development tools."
sections:
- type: hero
compact: true
eyebrow: "pacman · AUR · Flathub · mise"
title: "The software you'd install anyway."
subhead: "CoreDesktop installs a lot of useful software, mostly for work at Federated Computer, but you may find it useful too. Missing something? Suggest it, or send in a PR."
tiles: ["neovim", "Firefox", "Element"]
ctas:
- label: "Suggest a title"
url: "/contribute/"
style: primary
- type: table
kicker: "Four sources"
headline: "Where the software comes from."
lede: "Each source has its own list in the repository, so you can see exactly what's installed."
headers: ["Source", "What it installs", "Where it's listed"]
rows:
- ["pacman", "Arch's own packages: neovim, tmux, Go, Rust, Docker, Tailscale, Element, LibreOffice and more", "[packages.conf](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/packages.conf)"]
- ["AUR", "Community packages, built and kept up to date with yay: Helium Browser, Winboat and more", "[packages.conf](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/packages.conf)"]
- ["Flathub", "48 desktop apps in their own sandboxes", "[install-flatpaks.sh](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/install-flatpaks.sh)"]
- ["mise", "Ruby and Rails", "[install-mise-ruby-rails.sh](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/install-mise-ruby-rails.sh)"]
- type: cards
kicker: "From Flathub"
headline: "48 desktop apps, ready on first login."
lede: "Want more? Visit [flathub.org](https://flathub.org)."
columns: 3
items:
- label: "Browsers"
title: "Every browser you test against"
body: "Chrome, Chromium, Firefox, Brave, Zen and Vivaldi, plus Helium from the AUR as the default. Pick another in Settings › Apps › Default Apps."
- label: "Messaging"
title: "Talk to anyone"
body: "Signal, Telegram, Discord, Revolt and FluffyChat, Element from pacman, and Zoom for meetings."
- label: "Email & notes"
title: "Write it down"
body: "Thunderbird and Evolution for email; Obsidian, Logseq and Xournal++ for notes; Apostrophe for Markdown writing."
- label: "Media"
title: "Make and play media"
body: "Kdenlive for video editing, OBS for recording, Audacity for audio, Inkscape for vector graphics, Scribus for page layout, Spotify and Jellyfin."
- label: "Developers"
title: "Code and data"
body: "VS Code and VSCodium (VS Code without the Microsoft telemetry), Postman, DBeaver and Beekeeper Studio."
- label: "Local AI"
title: "Models on your own machine"
body: "Alpaca and LM Studio run language models locally, with nothing leaving your computer."
- label: "Remote"
title: "Reach other machines"
body: "Remmina and RustDesk for remote desktops, LocalSend to send files to nearby devices, and Trayscale for Tailscale."
- label: "Utilities"
title: "The useful little things"
body: "Boxes for virtual machines, Impression to write ISOs to USB sticks, Warehouse to manage Flatpaks, Extension Manager for GNOME, and Helvum for audio routing."
- label: "And more"
title: "Downtime included"
body: "qBittorrent, RetroArch and others. See [install-flatpaks.sh](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/install-flatpaks.sh) for the full list."
- type: split
kicker: "Development tools"
headline: "A full toolchain, out of the box."
lede: "Everything you need to build, run and ship, including three terminals: the GNOME console, kitty and ghostty."
columns:
- title: "Languages & runtimes"
items:
- "Go, Rust, Python, Node.js, npm and Bun"
- "Ruby and Rails, through mise"
- "Hugo and Dart Sass for websites"
- "Docker, Docker Compose and lazydocker"
- "pandoc and TeX Live for documents"
- title: "In the terminal"
items:
- "neovim (with kickstart.nvim), vim and tmux (with tpm)"
- "herdr, lazygit and difftastic"
- "ripgrep, fd, fzf, bat, eza, zoxide and yazi"
- "btop, htop, fastfetch and hyperfine"
- "nmap, mtr, sniffnet and whois"
- type: checklist
kicker: "On the desktop"
headline: "Also from pacman and the AUR."
items:
- "**LibreOffice** for documents, spreadsheets and slides"
- "**Bitwarden** for passwords"
- "**Element** for Matrix chat"
- "**GIMP**, **Flameshot** and **ImageMagick** for images"
- "**VLC** and **mpv** for video"
- "**Winboat** to run Windows apps"
- "**Cline Desktop**, in the AI sandbox"
- "**GNOME Tweaks** and the extra GNOME apps"
- type: final-cta
headline: "Something missing?"
body: "Tell us which titles or services you'd add, or send in a pull request."
ctas:
- label: "How to contribute"
url: "/contribute/"
style: primary
- label: "packages.conf"
url: "https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/packages.conf"
style: ghost
---
+106
View File
@@ -0,0 +1,106 @@
---
title: "System"
description: "How Federated CoreDesktop sets up your system: tiling, the shell, the firewall, Snapper snapshots, GPU drivers, mDNS, printing, open-port audits and sensible defaults."
sections:
- type: hero
compact: true
eyebrow: "Sensible defaults, all of them explained"
title: "What CoreDesktop sets up for you."
subhead: "A flexible tiling GNOME desktop, a better shell, a firewall that's actually on, snapshots before every update, and a handful of small fixes that add up."
tiles: ["Tiling", "Firewall", "Snapshots"]
- type: text
kicker: "Tiling"
headline: "Flexible tiling, all from the keyboard."
body: |
You end up with a GNOME system with a flexible tiling setup that works on any screen and really shines on widescreens. Hold <kbd>Super</kbd> (the Windows key or equivalent) and use the arrow keys to move windows around the screen.
To change the tiling, use the icon in the top right of your screen. You can set it up however you want.
- type: text
kicker: "Shell"
headline: "A better terminal, without the setup."
body: |
Your `~/.bashrc` sources `~/.local/share/coredesktop/shell/bashrc`, which sets up:
- the **starship** prompt (your own `~/.config/starship.toml` wins if you have one)
- **zoxide**: `z {part of a path}` jumps to a directory you've used before
- **fzf** key bindings: <kbd>Ctrl</kbd>+<kbd>R</kbd> searches history, <kbd>Ctrl</kbd>+<kbd>T</kbd> inserts a file path
- **eza** for `ls`, `ll`, `la` and `lt`
- the aliases and functions in [shell/](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/shell)
Anything you add to `~/.bashrc` after the CoreDesktop line overrides it.
- type: text
kicker: "Firewall"
headline: "ufw is on, and Docker can't get around it."
body: |
Incoming connections are blocked except SSH (22), mDNS (5353/udp), LocalSend (53317) and anything arriving over Tailscale.
Docker normally publishes container ports around ufw, so **ufw-docker** is installed too. To let a container's port through, or to open a port for something else, such as a dev server you want to reach from another machine:
```
sudo ufw-docker allow {container} {port}
sudo ufw allow {port}/tcp
sudo ufw status
```
To see every open port and who can reach it, run [audit](/utilities/#audit).
- type: text
id: snapshots
kicker: "Snapshots"
headline: "Roll back a bad update."
body: |
If `/` is btrfs (the archinstall default), Snapper takes a snapshot of `/` before every `update` and keeps the last 5. `/home` is a separate subvolume and isn't included, so rolling back never touches your files. `sudo snapper -c root list` shows the snapshots.
These snapshots can't be picked from the boot menu. To roll back, boot the Arch ISO and replace the `@` subvolume with a snapshot:
```
mount -o subvolid=5 /dev/{root partition} /mnt
mv /mnt/@ /mnt/@.broken
btrfs subvolume snapshot /mnt/@.snapshots/{number}/snapshot /mnt/@
reboot
```
If the disk is encrypted, open it with `cryptsetup open` first and mount the opened device. Once the system works again, free the space the broken root used:
```
sudo mount -o subvolid=5 /dev/{root partition} /mnt
sudo btrfs subvolume delete /mnt/@.broken
sudo umount /mnt
```
- type: features
kicker: "Hardware & network"
headline: "Drivers, printing and your LAN."
items:
- label: "GPU drivers"
body: "The Vulkan driver for Intel and AMD GPUs. For NVIDIA, if archinstall's proprietary driver wasn't chosen: the open kernel modules for GTX 16xx / RTX 20xx and newer, or the 580xx legacy driver back to the GTX 900 series. Reboot afterwards."
- label: "mDNS"
body: "Reach machines on your LAN as `machine.local`, e.g. `ssh machine.local`. Avahi and nss-mdns are set up ahead of systemd-resolved, so the two don't conflict."
- label: "Printing"
body: "The CUPS printing service is turned on. This may need more work to just work with other CoreDesktop machines."
- type: checklist
kicker: "System defaults"
headline: "Small fixes that add up."
items:
- "SSH connections notice a dropped link within a minute instead of hanging (override per host in `~/.ssh/config`)."
- "Logins allow 10 wrong passwords before locking the account for 2 minutes. Arch's default is 3 tries, then 10 minutes."
- "Shutdown waits at most 10 seconds for a service that won't stop, instead of 90."
- "If memory runs out, systemd-oomd closes the app causing it, instead of the whole desktop freezing."
- "Boot no longer waits for the network."
- "Commands run over SSH (`ssh {machine} {command}`) can find tools in `~/.local/bin` and mise."
- type: callout
text: "On a machine without systemd-resolved, set up mDNS yourself with `bash ~/.local/share/coredesktop/fixmdns.sh`. See the [Arch wiki](https://wiki.archlinux.org/title/Avahi#Hostname_resolution) for more."
- type: final-cta
headline: "Keep it all current with one command."
body: "`update` snapshots first, then updates everything, and tells you what failed."
ctas:
- label: "How updates work"
url: "/utilities/#update"
style: primary
---
+215
View File
@@ -0,0 +1,215 @@
---
title: "Utilities"
description: "The CoreDesktop commands: update, refresh, version, audit, configure and reset. Keep your system current, check your version and open ports, connect your Federated Core and back up, or start over."
sections:
- type: hero
compact: true
eyebrow: "update · refresh · version · audit · configure · reset"
title: "A few commands keep it all running."
subhead: "CoreDesktop comes with a handful of utilities. Type one in any terminal to keep your system current, see what's open, connect your Core, or start over."
logTitle: "CoreDesktop utilities"
log:
- tag: "update"
text: "Snapshot, then update everything"
- tag: "refresh"
text: "Pull in new CoreDesktop additions"
- tag: "version"
text: "Show what this machine is running"
- tag: "audit"
text: "Show open ports and who can reach them"
- tag: "configure"
text: "Connect your Core, Tailscale and backups"
- tag: "reset"
text: "Back to the state right after install"
- done: true
text: "Type any of them in a terminal."
- type: cards
kicker: "At a glance"
headline: "Six commands, one job each."
columns: 3
items:
- label: "update"
title: "Keep everything current"
body: "Snapshots your system, then updates Arch, GNOME, AUR packages, Flatpaks, Ruby, extensions and firmware."
link: "/utilities/#update"
linktext: "How update works"
- label: "refresh"
title: "Get what's new"
body: "Runs the install script again to add any new applications or services."
link: "/utilities/#refresh"
linktext: "About refresh"
- label: "version"
title: "Know what you're running"
body: "Shows your CoreDesktop version, kernel and last update, and whether something newer is waiting."
link: "/utilities/#version"
linktext: "About version"
- label: "audit"
title: "See who can reach you"
body: "Lists every open network port, who can connect to it through the firewall, and the service behind it."
link: "/utilities/#audit"
linktext: "About audit"
- label: "configure"
title: "Sign in once"
body: "Connects your Federated Core, joins its Tailscale network, sets up backups and signs in your AI agents."
link: "/utilities/#configure"
linktext: "About configure"
- label: "reset"
title: "Start over, cleanly"
body: "Changes your installation back to the state it was in right after you installed it."
link: "/utilities/#reset"
linktext: "About reset"
- type: command
id: update
kicker: "update"
headline: "Keep your system up to date."
lede: "From time to time, you'll want to update your system. Hopefully you'll do it more than once a month."
command: "update"
note: "It's a good idea to reboot after an update, especially when a new Linux kernel comes in, which happens often enough on Arch."
- type: checklist
kicker: "What update does"
headline: "Each step in updates.d, in order."
lede: "update pulls the latest CoreDesktop, then runs each step in `~/.local/share/coredesktop/updates.d/`. If a step fails, the other steps still run, and the failed ones are listed at the end."
items:
- "Stops if there's less than 10 GiB free on `/`. Run `UPDATE_FORCE=1 update` to skip the check."
- "Snapshots `/` first, if [Snapper is set up](/system/#snapshots)."
- "Updates the Arch keyring, then Arch and GNOME, then AUR packages, Flatpaks, Ruby, CoreDesktop's pipx apps, GNOME extensions and firmware."
- "Warns you not to reboot if the initramfs failed to rebuild."
- "Runs any one-time migrations, the way existing machines pick up new CoreDesktop setup."
- "Removes packages installed only as dependencies that nothing needs anymore, and lists them. Packages CoreDesktop installs are never removed this way."
- type: callout
text: "To keep a package you use directly from being removed, run `sudo pacman -D --asexplicit <package>`. And if an update ever barfs, check the **Latest News** on [archlinux.org](https://archlinux.org) for fixes."
- type: command
id: refresh
kicker: "refresh"
headline: "Pull in new additions."
lede: "refresh downloads the latest CoreDesktop and runs through the original install script again, adding any new applications or services. Anything already installed is skipped."
command: "refresh"
note: "Run `update` after `refresh`."
- type: text
id: version
kicker: "version"
headline: "Which version am I running?"
body: |
CoreDesktop is a rolling release, so its version is the date of the latest CoreDesktop change on your machine, followed by that change's id:
```
$ version
CoreDesktop 2026.10.22 (c5f0651)
Kernel 7.2.11-arch1-1
Last update 2026-10-22 13:43
```
The kernel comes from Arch, so it's shown separately. version also tells you:
- if a newer version of CoreDesktop is available
- if a newer kernel is installed and waiting for a reboot
- if your copy of CoreDesktop has local changes (it says "modified")
In a script, `version --check` prints the newer version if there is one.
### You don't have to check by hand
A few minutes after you log in, and every few hours after that, CoreDesktop checks for a new version and shows a notification if there is one. Click it to run update in a terminal, or dismiss it. Once dismissed, you won't be notified again until there's an even newer version.
- type: text
id: audit
kicker: "audit"
headline: "See who can reach your machine."
body: |
```
audit
```
audit shows the network ports open on this computer. For each one it shows who can connect after [the firewall](/system/#firewall): only this computer, your Tailscale network, or your LAN. It also names the service that opened the port and explains why, for example SSH, printing, mDNS, Tailscale or LocalSend.
You can stop a service from there, which also keeps it from starting at boot, or start a stopped one again. update leaves the services you stop off. audit won't stop the ones the desktop, Files or the network need.
Run it with sudo rights so it can name the services run by root. `audit --list` only shows the ports.
- type: command
id: configure
kicker: "configure"
headline: "Sign in once, and it's all connected."
lede: "Some of what CoreDesktop installs needs you to sign in or make a choice first. configure shows what's set up and sets up the rest."
command: "configure"
note: "To set up one thing, name it, e.g. `configure hermes`. `configure --list` shows the names."
- type: features
kicker: "What configure covers"
headline: "Your Core, your network, your backups, your agents."
items:
- label: "Your Federated Computer Core"
body: "Give it your Superpanel's address (e.g. https://superpanel.example.com), your Core email, name and password. It adds Superpanel to your apps, your Nextcloud calendar, contacts and files and your email to GNOME Online Accounts, mounts your Nextcloud files at `/mnt/example.com`, and points Element at your Core's Matrix server."
- label: "Your Core's Tailscale network"
body: "Joins this computer to it through `headscale.example.com`, so you can reach your other machines. Set up your Core first. You sign in through a link it shows you; if this computer is on another Tailscale network, it moves it to your Core's."
- label: "Daily backups of your home folder"
body: "Encrypted restic backups to a `.backup-{machine name}` folder in your Nextcloud files. It keeps 7 daily, 4 weekly and 6 monthly backups, and leaves out caches and things that can be reinstalled."
- label: "Your AI agents"
body: "Signs you in to Claude Code, opencode and Hermes Agent, and lets you choose their model providers. See the [AI Sandbox](/ai-sandbox/)."
- type: callout
text: "**Save your backup passphrase.** configure shows it once. Keep it somewhere other than this computer, such as Bitwarden. Without it, the backups can't be restored."
- type: text
id: backups
kicker: "Backups"
headline: "How the backups work."
body: |
restic reaches Nextcloud directly through rclone, with its own Nextcloud app password, so the backup doesn't depend on the `/mnt` mount. The Nextcloud app passwords configure creates can be revoked in Nextcloud under **Settings › Security**.
To leave out more, list paths in `~/.config/coredesktop/backup-exclude`, one per line.
```
systemctl --user list-timers coredesktop-backup.timer
journalctl --user -u coredesktop-backup
```
The first shows when the next backup runs; the second shows how the last ones went.
- type: text
id: restoring-from-a-backup
kicker: "Restoring"
headline: "Restoring from a backup."
body: |
To see the backups and get files back:
```
source ~/.local/share/coredesktop/system/backup-env.sh
restic snapshots
restic restore latest --target ~/restored --include ~/Documents
```
### On a new computer
Run `configure core` and `configure backup` first. Then name the old computer's folder, and restic asks for the passphrase you saved:
```
source ~/.local/share/coredesktop/system/backup-env.sh .backup-{old machine name}
restic snapshots
```
- type: command
id: reset
kicker: "reset"
headline: "Start over from a clean install."
lede: "reset changes your CoreDesktop installation back to the state it was in right after you installed it. Use it when you've changed so much that starting again from a known-good setup is simpler than undoing things one by one."
command: "reset"
note: "Before you reset, make sure your [backup](/utilities/#backups) is current. Afterwards, run `update` to bring everything up to date."
- type: final-cta
headline: "Don't have a Federated Core yet?"
body: "Every app your business needs, unlimited users, one low price, and private AI that runs on it."
ctas:
- label: "Visit Federated Computer"
url: "https://federated.computer/"
style: primary
- label: "Contribute to CoreDesktop"
url: "/contribute/"
style: ghost
---