Files
coredesktop/skills/sibling-project-format.md
davidandClaude Opus 5.5 76fceee115 Add sibling command for installing and updating sibling projects
`sibling` asks for a git URL, clones the repo into
~/.local/share/siblings/<name>, runs its install.sh and confirms the
install. `sibling list` and `sibling remove` manage installed siblings.

updates.d/71-siblings.sh pulls every sibling during `update` and runs
its update.sh, reporting failures in the update summary.

Document the sibling contract in skills/sibling-project-format.md and
update the custom-hook guide to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:23:58 -06:00

8.3 KiB

Skill: Formatting a Repository as a CoreDesktop Sibling Project

Overview

A sibling project is a git repository that builds on CoreDesktop. Users install one with CoreDesktop's sibling command, and from then on CoreDesktop's update command keeps it up to date.

Follow this document when you are working in a sibling repository and need it to install and update correctly under CoreDesktop. A repository needs no special files to be installable. It becomes useful by adding two optional scripts at its top level:

File When it runs
install.sh Once, when the user runs sibling add, and again if they re-run it
update.sh On every update, right after the repo has been pulled

If you want full control over how the project updates, see sibling-project-updates.md (custom updates.d hooks) instead. Use one approach or the other, not both, or the project updates twice.

What CoreDesktop Does

sibling add <url> (or sibling, which asks for the URL)

  1. Works out the project name from the last part of the URL, dropping .git: git@gitea.federated.computer:david/my-tools.git → my-tools.
  2. Clones the repo into ~/.local/share/siblings/<name>, or, if that folder already holds a clone of the same URL, runs git pull --ff-only there.
  3. If install.sh exists, runs bash install.sh with the repo folder as the working directory. Its input and output are the user's terminal.
  4. Reports success only if every step above succeeded.

update

CoreDesktop runs its own update hooks in order (10-pacman.sh … 70-claude.sh). Next, updates.d/71-siblings.sh takes each sibling in alphabetical order and:

  1. Runs git pull --ff-only --quiet in its folder.
  2. If the pull succeeded and update.sh exists, runs bash update.sh with the repo folder as the working directory.

A failed pull or a non-zero exit from update.sh is printed and listed in update's "Done, with errors in: …" summary. Other siblings still update. CoreDesktop's end-of-run hooks (GNOME settings, firmware, cleanup, reboot check) run after all siblings.

sibling remove <name>

This only deletes ~/.local/share/siblings/<name>. CoreDesktop has no uninstall step for siblings, so anything install.sh set up elsewhere stays.

Rules for the Repository

Layout

  • Put install.sh and update.sh at the top level of the repo. Other names or locations are ignored.
  • Both scripts are run with bash, so they don't need to be executable, but a #!/bin/bash line keeps them runnable by hand.
  • Locate files relative to the script, not to a hard-coded path. The user may also clone the repo somewhere else and run install.sh by hand.
    SELF="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    

Environment

  • The scripts run as separate bash processes, so they inherit no variables or functions from CoreDesktop. In particular $COREDESKTOP is not set. Use the path directly:

    COREDESKTOP="$HOME/.local/share/coredesktop"
    
  • CoreDesktop's helpers are available by sourcing utils.sh:

    Function What it does
    install_packages ... Installs pacman/AUR packages via yay, skipping installed ones
    remove_packages ... Removes installed pacman/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
  • sudo prompts for a password as normal. CoreDesktop does not grant passwordless sudo to siblings.

install.sh

  • 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 is 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 under CoreDesktop) with install_script.

update.sh

  • 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.
  • The repo has already been pulled, so update.sh always runs its newest version. Use it to apply changes made since the last update: new packages, updated commands in ~/.local/bin, config migrations.
  • It's fine to omit update.sh if pulling the repo is enough, for example when ~/.local/bin holds symlinks into the repo.

Keep pulls working

update pulls with --ff-only and never merges or resets. A pull fails if:

  • History on the default branch is rewritten (force-pushed). Never do this.
  • Tracked files are edited in place in the clone and a new commit touches them. Scripts must not write into tracked files. Write generated files, caches and per-machine state outside the repo (e.g. ~/.config/<name>/), or into paths listed in .gitignore.

Authentication

sibling clones with plain git. A private repo works only if the user can already clone it (SSH key, credential helper, or a password typed at the prompt). Every later update needs the same access.

Templates

Share the install logic between the two scripts so that packages or commands added 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>"

Testing

Test in a throwaway home folder so nothing touches the real one. Point sibling at a local clone; it accepts any URL or path that git clone does.

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 is 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.

Checklist

  • The repo 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>