diff --git a/Configure-Items.md b/Configure-Items.md new file mode 100644 index 0000000..8940290 --- /dev/null +++ b/Configure-Items.md @@ -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 ...` | 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 `_done` check and a `setup_` 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. diff --git a/Configure.md b/Configure.md new file mode 100644 index 0000000..a05a0c0 --- /dev/null +++ b/Configure.md @@ -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.`). 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/`, shown as `` 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 ", 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/`. +- 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. diff --git a/Home.md b/Home.md new file mode 100644 index 0000000..e23608e --- /dev/null +++ b/Home.md @@ -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 ` | Run an AI agent outside its sandbox | diff --git a/How-CoreDesktop-Works.md b/How-CoreDesktop-Works.md new file mode 100644 index 0000000..b20e8a3 --- /dev/null +++ b/How-CoreDesktop-Works.md @@ -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. diff --git a/Installing.md b/Installing.md new file mode 100644 index 0000000..3e0dd7b --- /dev/null +++ b/Installing.md @@ -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 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 +``` + +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). diff --git a/Migrations.md b/Migrations.md new file mode 100644 index 0000000..18d0909 --- /dev/null +++ b/Migrations.md @@ -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/` **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/.sh; echo "exit: $?" # run one by hand to see the error +``` diff --git a/Sandboxed-AI-Agents.md b/Sandboxed-AI-Agents.md new file mode 100644 index 0000000..d079955 --- /dev/null +++ b/Sandboxed-AI-Agents.md @@ -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/.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. diff --git a/Sibling-Projects.md b/Sibling-Projects.md new file mode 100644 index 0000000..a26fb03 --- /dev/null +++ b/Sibling-Projects.md @@ -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 # same, without the prompt +sibling list # installed siblings, their URL and current commit +sibling remove # delete it +``` + +`sibling add`: + +1. Clones the repository into `~/.local/share/siblings/`. +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). diff --git a/Software-and-Settings.md b/Software-and-Settings.md new file mode 100644 index 0000000..825e10c --- /dev/null +++ b/Software-and-Settings.md @@ -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 ` or browse . 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 ` 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 `.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 /tcp # open a port, e.g. for a dev server +sudo ufw-docker allow # 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 `) 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. diff --git a/Test-Home.md b/Test-Home.md deleted file mode 100644 index 5d08b7b..0000000 --- a/Test-Home.md +++ /dev/null @@ -1 +0,0 @@ -Welcome to the Wiki. \ No newline at end of file diff --git a/Troubleshooting.md b/Troubleshooting.md new file mode 100644 index 0000000..21511e3 --- /dev/null +++ b/Troubleshooting.md @@ -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 . | +| `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 +``` + +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/` is empty, first check whether it's mounted: + +``` +mountpoint /mnt/ +mount /mnt/ +``` + +| Message | Fix | +|---|---| +| `user 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/`. | +| 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/`. | + +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/`. + +### 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 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 `. diff --git a/Update-Hooks.md b/Update-Hooks.md new file mode 100644 index 0000000..74fdd56 --- /dev/null +++ b/Update-Hooks.md @@ -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. diff --git a/Updating.md b/Updating.md new file mode 100644 index 0000000..647aa88 --- /dev/null +++ b/Updating.md @@ -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 +``` + +If Arch itself won't update, check the "Latest News" on . 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/ /mnt +mv /mnt/@ /mnt/@.broken +btrfs subvolume snapshot /mnt/@.snapshots//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/ /mnt +sudo btrfs subvolume delete /mnt/@.broken +sudo umount /mnt +``` diff --git a/_Sidebar.md b/_Sidebar.md new file mode 100644 index 0000000..ceb4f55 --- /dev/null +++ b/_Sidebar.md @@ -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)