Add CoreDesktop documentation
User pages: installing, configure, updating, software and settings, sandboxed AI agents and troubleshooting. Contributor pages: how CoreDesktop works, update hooks, migrations, configure items and sibling projects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -0,0 +1,84 @@
|
||||
# Configure Items
|
||||
|
||||
Each file in `configure.d/` is one item in the `configure` menu. To add an item, add a file.
|
||||
|
||||
## Naming
|
||||
|
||||
The file name sets both the order and the item's name. The number prefix is dropped: `configure.d/30-claude.sh` is shown third and can be run as `configure claude`.
|
||||
|
||||
Current items:
|
||||
|
||||
| File | Item |
|
||||
|---|---|
|
||||
| `10-core.sh` | Federated Computer Core: Superpanel, Tailscale, Nextcloud, email, files, Element |
|
||||
| `30-claude.sh` | Claude Code |
|
||||
| `31-opencode.sh` | opencode |
|
||||
| `32-hermes.sh` | Hermes Agent |
|
||||
|
||||
## What a file defines
|
||||
|
||||
| Name | Required | Purpose |
|
||||
|---|---|---|
|
||||
| `TITLE` | yes | Shown in the menu |
|
||||
| `DESCRIPTION` | yes | One line, shown after the title |
|
||||
| `is_configured` | yes | Returns 0 if the item is done. Its output is hidden. |
|
||||
| `run_configure` | yes | Sets the item up. Return non-zero if it wasn't set up. |
|
||||
| `is_installed` | no | If defined and it fails, the item is left out of the menu |
|
||||
|
||||
The file is sourced in a subshell, so variables and `cd` don't leak out.
|
||||
|
||||
## What's available
|
||||
|
||||
| Name | What it is |
|
||||
|---|---|
|
||||
| `$COREDESKTOP` | `~/.local/share/coredesktop` |
|
||||
| `confirm "Question?"` | Yes/no question, default **no** |
|
||||
| `confirm_yes "Question?"` | Yes/no question, default **yes** |
|
||||
| `unsandboxed <agent> ...` | Runs an AI agent's real command. Setting an agent up writes outside its sandbox, so use this rather than the sandboxed command. |
|
||||
|
||||
`~/.local/bin` is on `PATH`.
|
||||
|
||||
## Example
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
TITLE="Claude Code"
|
||||
DESCRIPTION="Sign in to Anthropic"
|
||||
|
||||
is_installed() {
|
||||
command -v claude
|
||||
}
|
||||
|
||||
is_configured() {
|
||||
claude auth status
|
||||
}
|
||||
|
||||
run_configure() {
|
||||
echo " 1) Claude subscription (Pro, Max, Team or Enterprise)"
|
||||
echo " 2) Anthropic Console (pay for API usage)"
|
||||
local choice
|
||||
read -rp "How do you pay for Claude? [1] " choice
|
||||
case "$choice" in
|
||||
""|1) claude auth login ;;
|
||||
2) claude auth login --console ;;
|
||||
*) echo "Choose 1 or 2."; return 1 ;;
|
||||
esac
|
||||
}
|
||||
```
|
||||
|
||||
## Items with several steps
|
||||
|
||||
`10-core.sh` shows the pattern for an item made of several parts. Each part has a `<part>_done` check and a `setup_<part>` function, and a `step` helper does the rest:
|
||||
|
||||
- skips parts that are already done
|
||||
- asks before each of the others
|
||||
- carries on when one part fails, and reports the failure at the end
|
||||
|
||||
That way, running `configure` again only redoes what's missing.
|
||||
|
||||
Guidelines:
|
||||
|
||||
- **Remember answers.** Save what the user typed, like `~/.config/coredesktop/core.conf`, and offer it as the default next time.
|
||||
- **Don't keep passwords** in files or variables longer than needed. Pass them on stdin, not as arguments, so they don't show in the process list. Prefer revocable tokens, as `10-core.sh` does with Nextcloud app passwords.
|
||||
- **Check the real state** in `is_configured` and the `_done` checks, not just a marker file, so the menu stays accurate if the user changes something by hand.
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
# Configure
|
||||
|
||||
Some of what CoreDesktop installs needs you to sign in or make a choice first. Run:
|
||||
|
||||
```
|
||||
configure
|
||||
```
|
||||
|
||||
It lists each item as **done** or **to do**. Choose a number to set one up, `a` to set up everything still to do, or `q` to quit. It's safe to run again: finished steps show as "already set up" and are skipped.
|
||||
|
||||
```
|
||||
configure # menu
|
||||
configure core # set up one item by name
|
||||
configure --list # show what's set up, and the item names
|
||||
```
|
||||
|
||||
## Federated Computer Core (`configure core`)
|
||||
|
||||
It asks for:
|
||||
|
||||
- your Superpanel's address, e.g. `https://superpanel.example.com`
|
||||
- your Core email address
|
||||
- your name, as shown on email you send
|
||||
- your Core password, if Nextcloud, email or files still need setting up
|
||||
|
||||
Then it offers each of these in turn:
|
||||
|
||||
| Step | What it does |
|
||||
|---|---|
|
||||
| Superpanel | Adds Superpanel to your applications |
|
||||
| Tailscale | Joins this computer to your Core's Tailscale network (`headscale.<domain>`). It prints a link to open and sign in. |
|
||||
| Nextcloud | Adds Nextcloud to GNOME Online Accounts, for calendar, contacts and files |
|
||||
| Email | Adds your Core email to GNOME Online Accounts |
|
||||
| Files | Mounts your Nextcloud files at `/mnt/<domain>`, shown as `<domain>` in the Files sidebar |
|
||||
| Element | Points Element at your Core's Matrix server, so you only need to choose "Sign in" |
|
||||
|
||||
What you entered is saved in `~/.config/coredesktop/core.conf`, so next time the answers are filled in for you.
|
||||
|
||||
### Passwords
|
||||
|
||||
Your Core password is only used while `configure` runs. For Nextcloud and the files mount, `configure` creates a Nextcloud **app password** instead of storing your Core password. It shows in Nextcloud under **Settings > Security** as "CoreDesktop on <computer name>", where you can revoke it. Email uses your Core password, which GNOME keeps in its keyring.
|
||||
|
||||
### Your Nextcloud files
|
||||
|
||||
The files are mounted with davfs2:
|
||||
|
||||
- They're mounted each time you log in to the desktop, not at boot, and not for SSH-only logins.
|
||||
- If they aren't mounted, run `mount /mnt/<domain>`.
|
||||
- Mounting without sudo requires you to be in the `network` group. `configure` adds you, but the group only takes effect at your next login.
|
||||
|
||||
See [Troubleshooting](Troubleshooting#nextcloud-files) if the folder is empty.
|
||||
|
||||
## AI agents
|
||||
|
||||
| Item | What it asks |
|
||||
|---|---|
|
||||
| `configure claude` | Whether you pay with a Claude subscription or the Anthropic Console, then signs you in |
|
||||
| `configure opencode` | Which AI providers to sign in to. Pick models inside opencode with `/models`. |
|
||||
| `configure hermes` | Nous Portal, or another provider such as OpenRouter, OpenAI or Anthropic |
|
||||
|
||||
See [Sandboxed AI Agents](Sandboxed-AI-Agents) for how the agents run.
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
# CoreDesktop
|
||||
|
||||
CoreDesktop is a set of scripts that turns a fresh Arch Linux + GNOME install into a keyboard-driven tiling desktop with the software we use at Federated Computer. It isn't a distribution: Arch does the heavy lifting, and CoreDesktop installs, configures and keeps things up to date on top of it.
|
||||
|
||||
## Using CoreDesktop
|
||||
|
||||
- [Installing](Installing): install Arch, then CoreDesktop
|
||||
- [Configure](Configure): connect to your Federated Computer Core and sign in to the AI agents
|
||||
- [Updating](Updating): `update`, `refresh`, `version`, update notifications and snapshots
|
||||
- [Software and Settings](Software-and-Settings): software, shell, firewall and system defaults
|
||||
- [Sandboxed AI Agents](Sandboxed-AI-Agents): how opencode, Hermes Agent and Claude Code are contained
|
||||
- [Troubleshooting](Troubleshooting): common problems and fixes
|
||||
|
||||
## Working on CoreDesktop
|
||||
|
||||
- [How CoreDesktop Works](How-CoreDesktop-Works): repository layout and what runs when
|
||||
- [Update Hooks](Update-Hooks): adding a step to `update`
|
||||
- [Migrations](Migrations): getting a change onto machines that are already installed
|
||||
- [Configure Items](Configure-Items): adding something to `configure`
|
||||
- [Sibling Projects](Sibling-Projects): building your own project on top of CoreDesktop
|
||||
|
||||
## Quick reference
|
||||
|
||||
| Command | What it does |
|
||||
|---|---|
|
||||
| `update` | Update CoreDesktop, Arch, AUR, Flatpaks and everything else |
|
||||
| `refresh` | Re-run the installer to pick up newly added software |
|
||||
| `configure` | Set up your Core, Tailscale, Nextcloud, email and AI agents |
|
||||
| `version` | Show the CoreDesktop version, kernel and last update |
|
||||
| `sibling` | Install, list or remove sibling projects |
|
||||
| `unsandboxed <agent>` | Run an AI agent outside its sandbox |
|
||||
@@ -0,0 +1,70 @@
|
||||
# How CoreDesktop Works
|
||||
|
||||
CoreDesktop is a git repository of bash scripts. Each machine has a clone in `~/.local/share/coredesktop`, and `update` keeps that clone current with `git pull`. Changes reach machines when they're pushed to `main`.
|
||||
|
||||
## Repository layout
|
||||
|
||||
| Path | What's there |
|
||||
|---|---|
|
||||
| `install.sh` | The installer. `refresh` re-runs it. |
|
||||
| `update`, `refresh`, `configure`, `version`, `sibling` | User commands. They're copied to `~/.local/bin` by the installer and on every `update`. |
|
||||
| `utils.sh` | Shared helpers: `install_packages`, `remove_packages`, `remove_flatpaks`, `enable_services`, `install_script`, `install_pipx_apps`, `ensure_gext`, `run_migrations` |
|
||||
| `packages.conf` | Packages by category (`SYSTEM_UTILS`, `DEV_TOOLS`, `MAINTENANCE`, `DESKTOP`, `MEDIA`, `FONTS`), plus `PIPX` apps and `SERVICES` to enable |
|
||||
| `remove-packages.conf` | Packages and Flatpaks that `update` uninstalls |
|
||||
| `install-*.sh`, `claude.sh`, `bitwarden.sh` | Installer steps: Flatpaks, tmux plugins, mise/Ruby, Neovim, Claude Code, Bitwarden SSH agent |
|
||||
| `updates.d/` | The steps `update` runs, in filename order. See [Update Hooks](Update-Hooks). |
|
||||
| `migrations/` | One-time changes for machines that are already installed. See [Migrations](Migrations). |
|
||||
| `configure.d/` | The items `configure` offers. See [Configure Items](Configure-Items). |
|
||||
| `system/` | Firewall, Snapper, system defaults, GPU drivers, update notifications |
|
||||
| `gnome/` | GNOME extensions and their dconf settings |
|
||||
| `shell/` | bashrc, aliases, functions and the starship prompt |
|
||||
| `sandbox/` | The AI agent sandbox: the `agent` wrapper, `bin/` links and default `config/` |
|
||||
| `skills/` | Detailed guides for sibling project authors |
|
||||
|
||||
## Files on a machine
|
||||
|
||||
| Path | What it is |
|
||||
|---|---|
|
||||
| `~/.local/share/coredesktop` | The clone |
|
||||
| `~/.local/bin/{update,refresh,configure,version,sibling}` | Installed copies of the commands |
|
||||
| `~/.local/state/coredesktop/migrations/` | One empty file per migration that has run |
|
||||
| `~/.local/state/coredesktop/pacman-update.log` | Output of the last `pacman -Su` |
|
||||
| `~/.local/state/coredesktop/update-notified` | The newest version the user has been notified about |
|
||||
| `~/.config/coredesktop/core.conf` | What the user entered in `configure core` |
|
||||
| `~/.config/coredesktop/sandbox/` | The user's own sandbox rules |
|
||||
| `~/.local/share/siblings/` | Sibling projects |
|
||||
|
||||
## Install vs update
|
||||
|
||||
Getting a change onto every machine has two halves:
|
||||
|
||||
- **New machines** run `install.sh`.
|
||||
- **Existing machines** only run `update`.
|
||||
|
||||
| Kind of change | New machines | Existing machines |
|
||||
|---|---|---|
|
||||
| Add a package to `packages.conf` | `install.sh` | `10-pacman.sh` installs new packages automatically |
|
||||
| Remove a package | Take it out of `packages.conf` | Add it to `remove-packages.conf` |
|
||||
| Add a service to `SERVICES` | `install.sh` | `15-services.sh` enables it automatically |
|
||||
| Add a pipx app to `PIPX` | `install.sh` | `60-pipx.sh` installs it automatically |
|
||||
| Anything else in `install.sh` | `install.sh` | Add a [migration](Migrations) too |
|
||||
| Something to redo on every update | `install.sh` | Add an [update hook](Update-Hooks) |
|
||||
|
||||
If you change `install.sh` and existing machines need the change too, you must also add a migration.
|
||||
|
||||
## Scripts that replace themselves
|
||||
|
||||
`update` pulls the repository, which can rewrite the scripts that are running. To make that safe:
|
||||
|
||||
- `update`, `refresh`, `configure`, `update-check` and `sandbox/agent` wrap their whole body in `{ ...; exit; }`, so bash reads the entire file before running any of it.
|
||||
- `update` installs its fresh copy to `~/.local/bin/update`, then re-executes itself, so the rest of the run uses the new version.
|
||||
|
||||
Keep that wrapper in any new long-running script that lives in the repository.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Bash, with a `# Purpose :` header on standalone scripts.
|
||||
- Scripts must be safe to run again. Users re-run the installer to repair things, and migrations can run on fresh installs.
|
||||
- Check before changing: `is_installed`, `grep -q` before appending, `cmp -s` before replacing a file.
|
||||
- Write per-machine state outside the repository (`~/.config`, `~/.local/state`), never into tracked files, or `git pull` will fail.
|
||||
- Messages tell the user what happened and what to do next.
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# Installing
|
||||
|
||||
You install CoreDesktop in two stages: first Arch Linux with GNOME, then CoreDesktop on top.
|
||||
|
||||
## 1. Install Arch Linux
|
||||
|
||||
1. Download the Arch ISO from <https://archlinux.org/download/> and write it to a USB stick.
|
||||
2. Boot from the stick and run `archinstall`.
|
||||
3. Mostly take the defaults, except:
|
||||
- **Graphics:** if you have an NVIDIA GPU, choose the proprietary NVIDIA option. Choose the AMD option for AMD GPUs.
|
||||
- **Profile:** choose "Desktop", then "GNOME".
|
||||
- **Audio:** choose PipeWire.
|
||||
- **Filesystem:** keep the default, btrfs. CoreDesktop uses it to take a snapshot before every update (see [Updating](Updating#snapshots-and-rolling-back)).
|
||||
4. Reboot and log in to GNOME.
|
||||
|
||||
### No wired network?
|
||||
|
||||
Set up Wi-Fi from the installer with `iwctl`:
|
||||
|
||||
```
|
||||
device list
|
||||
station wlan0 scan
|
||||
station wlan0 get-networks
|
||||
station wlan0 connect <SSID>
|
||||
```
|
||||
|
||||
Replace `wlan0` with your device from `device list`, then check with `ping archlinux.org`. The [Arch wiki](https://wiki.archlinux.org/title/Network_configuration/Wireless) has more detail.
|
||||
|
||||
It's normal to get the Arch install wrong the first time or two. Just start again.
|
||||
|
||||
## 2. Install CoreDesktop
|
||||
|
||||
Open a terminal and run:
|
||||
|
||||
```
|
||||
wget -qO- https://gitea.federated.computer/david/coredesktop/raw/branch/main/install.sh | bash
|
||||
```
|
||||
|
||||
The installer:
|
||||
|
||||
- asks for your password once, at the start
|
||||
- updates Arch, then installs yay, the packages, Flatpaks, GNOME extensions, Ruby, Neovim, Claude Code and the sandboxed AI agents
|
||||
- turns on the firewall, Snapper snapshots, update notifications and the system defaults
|
||||
- installs the `update`, `refresh`, `configure`, `version` and `sibling` commands into `~/.local/bin`
|
||||
|
||||
CoreDesktop itself lives in `~/.local/share/coredesktop`.
|
||||
|
||||
If anything fails, run the same command again. It skips what's already done.
|
||||
|
||||
## 3. Finish setting up
|
||||
|
||||
1. Reboot when the installer finishes.
|
||||
2. Run `configure` to connect to your Federated Computer Core and sign in to the AI agents. See [Configure](Configure).
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
# Migrations
|
||||
|
||||
A migration is a script that `update` runs **once** on each machine. It's how machines installed before a change catch up with it.
|
||||
|
||||
## When you need one
|
||||
|
||||
If you change `install.sh`, or a script it calls, and machines that are already installed need the change too, add a migration. Package, service and pipx changes don't need one; see the table in [How CoreDesktop Works](How-CoreDesktop-Works#install-vs-update).
|
||||
|
||||
## Adding one
|
||||
|
||||
```bash
|
||||
cd ~/Projects/coredesktop
|
||||
$EDITOR migrations/$(date +%s).sh
|
||||
```
|
||||
|
||||
Usually the migration calls the same script as the installer, so both paths share one copy of the logic:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Turn on the ufw firewall
|
||||
bash "$HOME/.local/share/coredesktop/system/firewall.sh"
|
||||
```
|
||||
|
||||
## How they run
|
||||
|
||||
- `updates.d/12-migrations.sh` runs them during `update`, and `install.sh` runs them at the end of every install.
|
||||
- They run oldest first (by filename), with `bash`, as the user.
|
||||
- A migration is recorded in `~/.local/state/coredesktop/migrations/<name>` **only when it exits 0**.
|
||||
- The first failure stops the run, so a later migration never runs before an earlier one. The failed one is retried on the next `update`.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Make it safe to repeat.** Fresh installs run every migration, right after `install.sh` has done the same work. A failed migration also runs again.
|
||||
- **Exit non-zero on failure**, and only then. If you exit 0 when it didn't work, the migration is recorded and never runs again. If you exit non-zero when it did work, it blocks every later migration.
|
||||
- **Don't assume tools work yet.** Migrations run right after the pacman upgrade, before `60-pipx.sh` and `80-gnome-extensions.sh` repair things. After a Python upgrade, for example, pipx apps such as `gext` are broken. Source `utils.sh` and use a helper such as `ensure_gext` to repair what you need.
|
||||
- **Check the outcome, not the starting state.** For example, enable an extension even if it was already installed, in case an earlier run stopped half-way.
|
||||
- **Never rename or delete a migration** that has been pushed. Machines track migrations by filename.
|
||||
|
||||
## Example
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Install the Tailscale GNOME extension
|
||||
source "$HOME/.local/share/coredesktop/utils.sh"
|
||||
|
||||
ext="tailscale-gnome@diskmth.fr"
|
||||
ensure_gext || exit 1
|
||||
if ! ~/.local/bin/gext list | grep -q "$ext"; then
|
||||
~/.local/bin/gext --filesystem install "$ext" || exit 1
|
||||
fi
|
||||
# Enable even if it was already installed, in case an earlier run stopped short
|
||||
~/.local/bin/gext --filesystem enable "$ext"
|
||||
```
|
||||
|
||||
## Checking a machine
|
||||
|
||||
```bash
|
||||
ls ~/.local/share/coredesktop/migrations/ # all migrations
|
||||
ls ~/.local/state/coredesktop/migrations/ # the ones that have run
|
||||
bash ~/.local/share/coredesktop/migrations/<name>.sh; echo "exit: $?" # run one by hand to see the error
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
# Sandboxed AI Agents
|
||||
|
||||
CoreDesktop installs three AI coding agents: **opencode**, **Hermes Agent** and **Claude Code**. It runs all three in a sandbox, so an agent can't read your secrets or change files outside your project.
|
||||
|
||||
Before using an agent the first time, sign in with [`configure`](Configure#ai-agents).
|
||||
|
||||
## What the sandbox allows
|
||||
|
||||
A sandboxed agent:
|
||||
|
||||
- can change files only in the directory you start it from, plus its own settings, `/tmp` and a few package caches. Start it from a project directory: it refuses to start from your home folder or `/`.
|
||||
- can't read your SSH and GPG keys, password stores, keyrings, browser profiles, cloud and Git credentials, or the other agents' logins
|
||||
- can reach only AI providers and common developer sites: GitHub, Gitea, npm, PyPI, crates.io, RubyGems, the Go module proxy and archlinux.org
|
||||
|
||||
## How it works
|
||||
|
||||
| Agent | Sandbox |
|
||||
|---|---|
|
||||
| `opencode`, `hermes`, `hermes-agent` | Run inside Anthropic's [sandbox runtime](https://github.com/anthropics/sandbox-runtime) (`srt`), which uses bubblewrap and socat |
|
||||
| Hermes' gateway | Its background service, which lets you talk to Hermes over Matrix, runs in the same sandbox. It can also reach the Matrix server in Hermes' settings. |
|
||||
| Claude Code | Uses its own built-in sandbox for every command it runs. See `/sandbox` inside Claude. |
|
||||
|
||||
Typing an agent's name runs it sandboxed, because `sandbox/bin` comes first on your `PATH`. To run one without the sandbox:
|
||||
|
||||
```
|
||||
unsandboxed opencode
|
||||
```
|
||||
|
||||
## Allowing more
|
||||
|
||||
If an agent needs a site or folder the sandbox blocks, add it in:
|
||||
|
||||
- `~/.config/coredesktop/sandbox/base.json`, for every agent
|
||||
- `~/.config/coredesktop/sandbox/<agent>.json`, for one agent: `opencode.json` or `hermes.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"network": { "allowedDomains": ["docs.example.com"] },
|
||||
"filesystem": { "allowWrite": ["~/notes"] }
|
||||
}
|
||||
```
|
||||
|
||||
Your files only add to CoreDesktop's defaults, which are in `sandbox/config/` in the repository. The change applies the next time you start the agent. For Hermes' gateway, run `systemctl --user restart hermes-gateway`.
|
||||
|
||||
For Claude Code, change the `sandbox` section of `~/.claude/settings.json`. CoreDesktop only fills in defaults there and never overwrites what you've set.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Sibling Projects
|
||||
|
||||
A sibling project is another git repository that builds on CoreDesktop: extra tools, team-specific setup, dotfiles and so on. CoreDesktop installs it and keeps it up to date.
|
||||
|
||||
## Using siblings
|
||||
|
||||
```
|
||||
sibling # asks for the repository's git URL
|
||||
sibling add <url> # same, without the prompt
|
||||
sibling list # installed siblings, their URL and current commit
|
||||
sibling remove <name> # delete it
|
||||
```
|
||||
|
||||
`sibling add`:
|
||||
|
||||
1. Clones the repository into `~/.local/share/siblings/<name>`.
|
||||
2. Runs its `install.sh`, if it has one.
|
||||
|
||||
From then on, every `update` pulls each sibling and runs its `update.sh`, if it has one.
|
||||
|
||||
`sibling remove` only deletes the clone. Anything its `install.sh` set up elsewhere stays.
|
||||
|
||||
## Making a repository a sibling
|
||||
|
||||
A repository needs no special files to be installable. To do more, add either or both of these at the top level:
|
||||
|
||||
| File | When it runs |
|
||||
|---|---|
|
||||
| `install.sh` | Once, from the repository folder, when the user runs `sibling add`, and again if they re-run it |
|
||||
| `update.sh` | On every `update`, from the repository folder, after the pull |
|
||||
|
||||
Key rules:
|
||||
|
||||
- **The scripts inherit nothing from CoreDesktop.** Set `COREDESKTOP="$HOME/.local/share/coredesktop"` yourself, and source `$COREDESKTOP/utils.sh` for its helpers.
|
||||
- **Exit non-zero on failure.** `install.sh` may prompt; `update.sh` shouldn't, and must be safe to run every time.
|
||||
- **Keep `git pull --ff-only` working.** Never force-push the default branch, and never write into tracked files in the clone.
|
||||
- **Private repositories** work only if the user can already clone them, with an SSH key or credential helper.
|
||||
|
||||
The full guide, with templates, testing steps and a checklist, is in the repository: [`skills/sibling-project-format.md`](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/skills/sibling-project-format.md).
|
||||
|
||||
## Custom update hooks
|
||||
|
||||
For full control over how it updates, a sibling can instead copy its own hook, numbered 72–79, into CoreDesktop's `updates.d/` from its `install.sh`. Use one approach or the other, not both, or the project updates twice. See [`skills/sibling-project-updates.md`](https://gitea.federated.computer/Federated_Computer/coredesktop/src/branch/main/skills/sibling-project-updates.md) and [Update Hooks](Update-Hooks).
|
||||
@@ -0,0 +1,87 @@
|
||||
# Software and Settings
|
||||
|
||||
## The desktop
|
||||
|
||||
GNOME with the **Tiling Shell** extension, set up as a three-column layout that works especially well on ultrawide monitors. The Tiling Shell icon in the top bar changes the layout. **Super + arrow keys** move windows between tiles.
|
||||
|
||||
The **Tailscale** GNOME extension shows your tailnet status in the top bar.
|
||||
|
||||
## Where software comes from
|
||||
|
||||
| Source | Defined in | Examples |
|
||||
|---|---|---|
|
||||
| pacman | `packages.conf` | GNOME, Neovim, tmux, Go, Rust, Node, Docker, Tailscale, Element, LibreOffice, Ghostty, kitty, opencode |
|
||||
| AUR (via yay) | `packages.conf` | Helium browser, Winboat |
|
||||
| Flathub | `install-flatpaks.sh` | Chrome, Firefox, Brave, Zen, VS Code, VSCodium, Signal, Telegram, Thunderbird, Obsidian, Logseq, OBS, Kdenlive, Inkscape, Zoom, Trayscale, LocalSend, Boxes and more |
|
||||
| mise | `install-mise-ruby-rails.sh` | Ruby and Rails |
|
||||
| pipx | `packages.conf` (`PIPX`) | terrahour |
|
||||
| Their own installers | `claude.sh`, `sandbox/setup.sh` | Claude Code, Hermes Agent |
|
||||
|
||||
`update` installs anything newly added to these lists, and removes anything listed in `remove-packages.conf`.
|
||||
|
||||
To install more apps yourself, use `yay -S <package>` or browse <https://flathub.org>. To suggest something for everyone, open an issue or pull request.
|
||||
|
||||
## Shell
|
||||
|
||||
`~/.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**: Ctrl-R searches history, Ctrl-T inserts a file path, Alt-C changes directory
|
||||
- **eza** for `ls`, `ll`, `la` and `lt`
|
||||
- aliases: `g` (git), `lg` (lazygit), `d` (docker), `ld` (lazydocker), `gcm`, `gcam`, `gcad`, `..`, `...`, `ff` (fuzzy-find with preview), `eff` (open the result in your editor)
|
||||
- functions:
|
||||
- `n`: open Neovim
|
||||
- `open`: open a file or URL in its default app
|
||||
- `compress` and `decompress`: make and unpack `.tar.gz` archives
|
||||
- `fip`, `dip` and `lip`: start, stop and list SSH port forwards
|
||||
- `ga` and `gd`: create and remove git worktrees
|
||||
|
||||
Anything you add to `~/.bashrc` after the CoreDesktop line overrides it.
|
||||
|
||||
## Networking
|
||||
|
||||
- **mDNS:** reach other machines on your LAN as `<name>.local`, and SSH to this one the same way. If systemd-resolved is enabled, the installer applies a fix so mDNS still works. For the details, see `fixmdns.sh` and the [Arch wiki](https://wiki.archlinux.org/title/Avahi#Hostname_resolution).
|
||||
- **Tailscale:** installed and running. `configure core` joins it to your Core's network.
|
||||
- **Printing:** CUPS is enabled.
|
||||
|
||||
## Firewall
|
||||
|
||||
ufw is on. Incoming connections are blocked, except:
|
||||
|
||||
- SSH (22)
|
||||
- mDNS (5353/udp)
|
||||
- LocalSend (53317)
|
||||
- anything arriving over Tailscale
|
||||
|
||||
ufw-docker is installed too, because otherwise ports published by Docker containers get around ufw.
|
||||
|
||||
```
|
||||
sudo ufw status # show the rules
|
||||
sudo ufw allow <port>/tcp # open a port, e.g. for a dev server
|
||||
sudo ufw-docker allow <container> <port> # let a container's port through
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
Docker is installed and running, and you're in the `docker` group, which takes effect from your next login.
|
||||
|
||||
## GPU drivers
|
||||
|
||||
The installer adds the Vulkan driver for Intel and AMD GPUs. For NVIDIA GPUs, if archinstall's proprietary driver wasn't chosen, it installs NVIDIA's driver:
|
||||
|
||||
- the open kernel modules for GTX 16xx / RTX 20xx and newer
|
||||
- the 580xx legacy driver for older cards, back to the GTX 900 series
|
||||
|
||||
## System defaults
|
||||
|
||||
- SSH connections notice a dropped link within a minute instead of hanging. Override this 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 freezing the whole desktop.
|
||||
- Boot doesn't wait for the network.
|
||||
- Commands run over SSH (`ssh <machine> <command>`) can find tools in `~/.local/bin` and mise.
|
||||
|
||||
## Backups
|
||||
|
||||
[Migrate](https://github.com/CyphrRiot/Migrate) is installed as `migrate`, and borg and Déjà Dup are available too.
|
||||
-1
@@ -1 +0,0 @@
|
||||
Welcome to the Wiki.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Troubleshooting
|
||||
|
||||
## Install and update
|
||||
|
||||
### The installer stopped part way
|
||||
|
||||
Run it again: each step skips what's already done. The usual causes are a sudo password timing out or a network hiccup.
|
||||
|
||||
### `update` says "Done, with errors in: …"
|
||||
|
||||
Scroll up to that step's output. Each step runs on its own, so the rest of the update still happened. Common ones:
|
||||
|
||||
| Step | Usual cause |
|
||||
|---|---|
|
||||
| `10-pacman.sh` | An Arch change that needs a manual step. Check the "Latest News" on <https://archlinux.org>. |
|
||||
| `12-migrations.sh` | A one-time change failed. It's retried on every `update`, and later migrations wait for it. The output says which one failed. |
|
||||
| `20-aur.sh` | An AUR package failed to build. It usually fixes itself when the package is updated. |
|
||||
| `71-siblings.sh` | A sibling project couldn't pull, or its `update.sh` failed |
|
||||
|
||||
### "could not pull the latest CoreDesktop"
|
||||
|
||||
The CoreDesktop folder has local changes. `version` shows "modified" when this is the case. To see them:
|
||||
|
||||
```
|
||||
git -C ~/.local/share/coredesktop status
|
||||
```
|
||||
|
||||
Keep anything you need elsewhere, then discard the changes:
|
||||
|
||||
```
|
||||
git -C ~/.local/share/coredesktop checkout -- .
|
||||
```
|
||||
|
||||
### "Only N GiB free on /"
|
||||
|
||||
`update` needs 10 GiB free, because an upgrade that runs out of space can leave the system half-upgraded. Free up space, for example with `sudo paccache -rk1`. If you're sure, run `UPDATE_FORCE=1 update`.
|
||||
|
||||
### "Don't reboot yet: the initramfs failed to rebuild"
|
||||
|
||||
Rebooting now could leave the machine unbootable. Read the errors in `~/.local/state/coredesktop/pacman-update.log` and fix them first. If a reboot does fail, roll back to the snapshot taken before the update (see [Updating](Updating#snapshots-and-rolling-back)).
|
||||
|
||||
### A GNOME extension is missing or doesn't load
|
||||
|
||||
GNOME only loads new or updated extensions at login, so log out and back in first. If an extension still isn't there, check:
|
||||
|
||||
```
|
||||
~/.local/bin/gext list
|
||||
gnome-extensions info <extension-id>
|
||||
```
|
||||
|
||||
If `gext` itself fails with `ModuleNotFoundError`, a Python upgrade broke it. `update` reinstalls it.
|
||||
|
||||
## Configure
|
||||
|
||||
### Tailscale: "failed to connect to local tailscaled"
|
||||
|
||||
The Tailscale service isn't running. `configure` starts it now. On older versions, start it yourself and run `configure core` again:
|
||||
|
||||
```
|
||||
sudo systemctl enable --now tailscaled
|
||||
```
|
||||
|
||||
### Nextcloud files
|
||||
|
||||
If `/mnt/<domain>` is empty, first check whether it's mounted:
|
||||
|
||||
```
|
||||
mountpoint /mnt/<domain>
|
||||
mount /mnt/<domain>
|
||||
```
|
||||
|
||||
| Message | Fix |
|
||||
|---|---|
|
||||
| `user <you> must be member of group network` | `configure` added you to the `network` group, but it only takes effect at your next login. Log out and back in, or for now run `sudo -u $USER mount /mnt/<domain>`. |
|
||||
| Asks for a password, or 401 errors | The app password was revoked or is wrong. Run `configure core` again. |
|
||||
| Mounted, but empty | Check the WebDAV address in `/etc/fstab`. It should end with `/remote.php/dav/files/<your user>`. |
|
||||
|
||||
The folder is mounted when you log in to the desktop. If the network wasn't up yet, it won't be mounted; run `mount /mnt/<domain>`.
|
||||
|
||||
### Nextcloud says the password is wrong
|
||||
|
||||
`configure` checks your Core password against Nextcloud and gives you three tries. If you use two-factor sign-in, Nextcloud may refuse the password itself. In that case, create an app password in Nextcloud under **Settings > Security** and enter that instead.
|
||||
|
||||
## AI agents
|
||||
|
||||
### "Start <agent> from a project directory"
|
||||
|
||||
A sandboxed agent can change anything in the directory it starts in, so it refuses to start in your home folder or `/`. `cd` into a project first.
|
||||
|
||||
### An agent can't reach a site or write a folder
|
||||
|
||||
The sandbox blocked it. Add the domain or folder as shown in [Sandboxed AI Agents](Sandboxed-AI-Agents#allowing-more).
|
||||
|
||||
### "The sandbox (srt) isn't installed"
|
||||
|
||||
Run `update`. To use the agent without the sandbox in the meantime, run `unsandboxed <agent>`.
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# Update Hooks
|
||||
|
||||
`update` runs each `*.sh` file in `updates.d/` in filename order. To add a step to `update`, add a file there.
|
||||
|
||||
## How hooks run
|
||||
|
||||
For each hook, `update`:
|
||||
|
||||
1. Starts a subshell, so a `cd`, `set -e`, `exit` or stray variable can't affect other hooks.
|
||||
2. Sources the file.
|
||||
3. If the file defines `run_update`, calls it, but only if `is_installed` isn't defined or returns true.
|
||||
4. If the subshell exits non-zero, adds the hook to "Done, with errors in: …" at the end. The remaining hooks still run.
|
||||
|
||||
`$COREDESKTOP` is set to `~/.local/share/coredesktop`. Nothing from earlier hooks is available, so source `utils.sh` if you need its helpers. Source it **before** defining your own `is_installed`, because `utils.sh` has a pacman-specific function with that name.
|
||||
|
||||
Sudo is already authenticated and kept alive for the whole run. Hooks shouldn't prompt for anything else.
|
||||
|
||||
## Two styles
|
||||
|
||||
Top-level code, for steps that always apply:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
COREDESKTOP="$HOME/.local/share/coredesktop"
|
||||
source "$COREDESKTOP/utils.sh"
|
||||
|
||||
echo "Checking for new services..."
|
||||
enable_services "${SERVICES[@]}"
|
||||
```
|
||||
|
||||
Functions, for steps that only apply on some machines:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
is_installed() {
|
||||
command -v fwupdmgr &>/dev/null
|
||||
}
|
||||
|
||||
run_update() {
|
||||
echo "Checking for firmware updates..."
|
||||
...
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
Return non-zero from `run_update` to report a failure.
|
||||
|
||||
## Order
|
||||
|
||||
| Hook | Purpose |
|
||||
|---|---|
|
||||
| `09-snapshot.sh` | Snapper snapshot of `/` (btrfs only) |
|
||||
| `10-pacman.sh` | Remove dropped packages, update keyring and Arch, install new packages |
|
||||
| `12-migrations.sh` | One-time [migrations](Migrations) |
|
||||
| `15-services.sh` | Enable new services |
|
||||
| `16-update-notify.sh` | Update-notification timer |
|
||||
| `20-aur.sh` | AUR packages; rebuilds yay if a pacman upgrade broke it |
|
||||
| `30-flatpak.sh` | Flatpaks |
|
||||
| `40-ruby.sh` | mise, Ruby and gems |
|
||||
| `45-tmux.sh` | tmux plugins |
|
||||
| `46-neovim.sh` | Neovim plugins |
|
||||
| `50-bitwarden.sh` | Bitwarden SSH agent |
|
||||
| `60-pipx.sh` | pipx apps; rebuilds them after a Python upgrade |
|
||||
| `65-migrate.sh` | Migrate backup tool |
|
||||
| `70-claude.sh` | Claude Code |
|
||||
| `71-siblings.sh` | Sibling projects |
|
||||
| `72-sandbox.sh` | Sandbox runtime and Hermes Agent |
|
||||
| `80-gnome-extensions.sh` | GNOME extensions |
|
||||
| `85-gnome-settings.sh` | GNOME extension settings |
|
||||
| `90-firmware.sh` | Report firmware updates |
|
||||
| `95-cleanup.sh` | Flatpak and pacman cache cleanup, orphaned packages |
|
||||
| `99-reboot-check.sh` | Say whether a reboot is needed |
|
||||
|
||||
Pick a number that puts your hook after whatever it depends on. Anything that runs before `60-pipx.sh` can't rely on pipx apps working, and anything before `20-aur.sh` can't rely on yay.
|
||||
|
||||
## Testing
|
||||
|
||||
Run one hook the way `update` does:
|
||||
|
||||
```bash
|
||||
( COREDESKTOP=~/.local/share/coredesktop
|
||||
source updates.d/NN-name.sh
|
||||
if declare -f run_update >/dev/null; then
|
||||
! declare -f is_installed >/dev/null || is_installed && run_update
|
||||
fi ); echo "exit: $?"
|
||||
```
|
||||
|
||||
Run it twice to make sure the second run does nothing harmful.
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# Updating
|
||||
|
||||
## `update`
|
||||
|
||||
Run this at least once a month:
|
||||
|
||||
```
|
||||
update
|
||||
```
|
||||
|
||||
It pulls the latest CoreDesktop, then runs each step in `~/.local/share/coredesktop/updates.d/` in order. Among other things, it:
|
||||
|
||||
- stops if there's less than 10 GiB free on `/` (`UPDATE_FORCE=1 update` skips this check)
|
||||
- takes a Snapper snapshot of `/` first, on btrfs
|
||||
- updates the Arch keyring, then Arch and GNOME, AUR packages, Flatpaks, Ruby, pipx apps, GNOME extensions, sibling projects and the AI agents
|
||||
- installs packages newly added to CoreDesktop, and removes ones it has dropped
|
||||
- runs any one-time [migrations](Migrations) this machine hasn't had yet
|
||||
- reports available firmware updates; it doesn't install them (run `fwupdmgr update` yourself)
|
||||
- removes packages nothing needs any more, and lists them
|
||||
- tells you if you should reboot, or warns you **not** to if the initramfs failed to rebuild
|
||||
|
||||
You type your password once; `update` keeps sudo alive until it's done. If a step fails, the rest still run, and the failures are listed at the end:
|
||||
|
||||
```
|
||||
Done, with errors in: 20-aur.sh
|
||||
```
|
||||
|
||||
To keep a package that `update` removes as unneeded, mark it as one you installed yourself:
|
||||
|
||||
```
|
||||
sudo pacman -D --asexplicit <package>
|
||||
```
|
||||
|
||||
If Arch itself won't update, check the "Latest News" on <https://archlinux.org>. It often explains a needed manual step.
|
||||
|
||||
## Update notifications
|
||||
|
||||
A few minutes after you log in, and every 4 hours after that, CoreDesktop checks for a new version. If there is one, a notification appears. Click it to run `update` in a terminal. If you dismiss it, you won't be notified again until there's an even newer version.
|
||||
|
||||
## `version`
|
||||
|
||||
```
|
||||
$ version
|
||||
CoreDesktop 2026.10.22 (c5f0651)
|
||||
Kernel 7.2.11-arch1-1
|
||||
Last update 2026-10-22 13:43
|
||||
```
|
||||
|
||||
CoreDesktop is a rolling release, so its version is the date and id of the latest change on your machine. `version` also tells you:
|
||||
|
||||
- if a newer CoreDesktop is available
|
||||
- if a newer kernel is waiting for a reboot
|
||||
- if the CoreDesktop folder has local changes ("modified"), which can stop `update` from pulling
|
||||
|
||||
## `refresh`
|
||||
|
||||
`refresh` re-runs the full installer. `update` already installs new packages and runs migrations, so you rarely need `refresh`. Use it to repair an install, or to pick up something that only the installer sets up. Run `update` afterwards.
|
||||
|
||||
## Snapshots and rolling back
|
||||
|
||||
If `/` is btrfs (the archinstall default), Snapper snapshots `/` 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
|
||||
```
|
||||
|
||||
These snapshots can't be chosen from the boot menu. To roll back after a bad update, 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
|
||||
```
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
**Using CoreDesktop**
|
||||
|
||||
- [Home](Home)
|
||||
- [Installing](Installing)
|
||||
- [Configure](Configure)
|
||||
- [Updating](Updating)
|
||||
- [Software and Settings](Software-and-Settings)
|
||||
- [Sandboxed AI Agents](Sandboxed-AI-Agents)
|
||||
- [Troubleshooting](Troubleshooting)
|
||||
|
||||
**Working on CoreDesktop**
|
||||
|
||||
- [How CoreDesktop Works](How-CoreDesktop-Works)
|
||||
- [Update Hooks](Update-Hooks)
|
||||
- [Migrations](Migrations)
|
||||
- [Configure Items](Configure-Items)
|
||||
- [Sibling Projects](Sibling-Projects)
|
||||
Reference in New Issue
Block a user