commit 32b382891cf4716043f4283a3363bbe60d363c3b Author: Guofang Date: Wed Nov 4 22:43:39 2026 +0800 Initial commit Co-Authored-By: Claude Sonnet 5.5 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..05b3159 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# AGENTS.md + +## Project Overview + +Collection of post-install initialization scripts, one directory per OS +(`debian/`, `macos/`, ...). Each directory has its own `AGENTS.md`; the nearest +one takes precedence over this file. + +## Shared Rules + +- One self-contained script per OS directory; do not share code across OSes + via sourced libraries, so each script can be copied and run on its own. +- Scripts must be idempotent, check the OS/version and privileges early, and + fail with actionable errors. +- Never store secrets in the repository. Do not execute unverified remote + content (`curl | sh`). +- Do not change SSH policy, networking, disks, boot config, or user + credentials without an explicit opt-in switch. +- Keep README.md's OS table in sync when adding or renaming scripts. +- Validate with `bash -n` (and `shellcheck` if available) before delivering. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9093d02 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# os-init + +Post-install initialization scripts, one directory per operating system. + +| Directory | Target | Script | +|-----------|--------|--------| +| `debian/` | Debian 13 (GNOME desktop) | `debian13-init.sh` | +| `macos/` | macOS | `macos-init.sh` | + +## Conventions + +- Each OS directory is self-contained: a single script, run directly on the + target machine, plus its own `AGENTS.md` for OS-specific rules. +- Scripts must be idempotent (safe to run repeatedly) and must not change + security-sensitive settings without an explicit opt-in. +- Add a new OS by creating `/` with `-init.sh` and adding a + row to the table above. diff --git a/debian/AGENTS.md b/debian/AGENTS.md new file mode 100644 index 0000000..8c87d24 --- /dev/null +++ b/debian/AGENTS.md @@ -0,0 +1,123 @@ +# AGENTS.md + +## Project Overview + +This directory maintains a single shell script for initializing a newly +installed Debian system. Except for this file and essential project documentation, do not +split functionality into additional scripts, configuration generators, or other +languages. Keep the initialization logic centralized, easy to review, and +directly executable on the target machine. + +## Scope + +This file applies to the `debian/` directory. The repository-level `AGENTS.md` +still applies; where the two conflict, this file takes precedence. + +## Target Machine + +- During development, debugging, and validation, you may connect to the target + machine with `ssh 192.168.122.130`. +- When the current user lacks sufficient privileges on the target machine, you + may elevate privileges with `sudo`. + +## Development Principles + +- Write Bash and use `#!/usr/bin/env bash` as the first line. +- New code must be compatible with the current Debian stable release. If a + command or option requires a specific version, document it in a comment or + the README. +- The script must support repeated execution. Creating users, installing + packages, writing configuration, and enabling services should be idempotent + wherever possible. Avoid duplicate entries and failures caused by resources + that already exist. +- Keep the single-script design. Prefer small functions with clear + responsibilities and use a `main` function as the entry point. +- Prefer `set -Eeuo pipefail`, and explicitly handle commands that may be + expected to fail. +- Double-quote variables unless word splitting or glob expansion is + intentionally required. Use `local` for local variables and clear names for + constants and environment variables. +- Prefer native Debian tools and repositories. Do not introduce third-party + repositories, runtimes, or external dependencies without a valid reason. +- Comments should explain reasons, compatibility constraints, or risks rather + than restating each line of code. + +## Security Requirements + +- Check for root privileges before operations that require them and provide a + clear error message. Do not silently elevate privileges inside the script. +- Never store passwords, tokens, private keys, or other sensitive information + in the repository, command-line arguments, or logs. +- Do not execute unverified remote content with patterns such as + `curl ... | sh` or `wget ... | bash`. +- Download external files over HTTPS and verify fixed versions, checksums, or + signatures whenever possible. +- Confirm target files and directories before changing system configuration. + When replacing important configuration, preserve a recoverable backup or use + a reviewable atomic write. +- Avoid broad or irreversible commands, including recursive deletion with + unvalidated variables, globally relaxed permissions, and unconditional + firewall resets. +- Do not change SSH login policy, network connectivity, disk partitions, boot + configuration, or existing user credentials without explicit authorization. + If the project explicitly requires such an operation, provide a prominent + warning and an explicit opt-in switch. +- Scope noninteractive APT settings to only the commands that require them. Do + not permanently change the user's environment. + +## Behavior and Output + +- Early in startup, check the runtime environment, Debian version, privileges, + and required commands. Fail with actionable error messages. +- Print concise and clear status messages for important steps. Write errors to + standard error and exit with a nonzero status. +- Prefer environment variables with safe defaults or command-line options for + user-selectable features, and provide `--help`. Do not unexpectedly block + unattended execution. +- Features with significant impact or machine-specific behavior must be + disabled by default and run only when explicitly enabled. +- Combine package installation into as few `apt-get install` operations as + practical, and avoid unnecessary `apt-get upgrade` or distribution upgrades. +- Do not assume a systemd service exists. Confirm that the relevant package and + service unit are available before enabling or restarting a service. + +## Change Constraints + +- Keep changes focused on Debian initialization. Do not add unrelated + functionality. +- Do not perform broad rewrites solely for style. Preserve existing behavior + and configuration options. +- Give new configuration options safe defaults and update script help and + related documentation. +- Clearly state in the delivery notes when a change alters system behavior, + default packages, or security policy. + +## Validation + +After modifying the script, run at least: + +```bash +bash -n ./*.sh +``` + +If ShellCheck is installed, also run: + +```bash +shellcheck ./*.sh +``` + +For argument parsing or pure function logic, use temporary directories and +mock input for targeted tests. Unless explicitly authorized by the user, do not +install or remove packages, modify `/etc`, manage users, change networking, +restart services, or reboot the current development machine during testing. +List any system-level behavior that cannot be safely validated and recommend +validation steps in a fresh Debian virtual machine. + +## Delivery Notes + +When completing a change, briefly describe: + +- Which initialization behavior changed. +- Whether default behavior or system security policy changed. +- Which static checks or tests were run. +- Which operations still require validation in a fresh Debian virtual machine. diff --git a/debian/debian13-init.sh b/debian/debian13-init.sh new file mode 100755 index 0000000..ffacd27 --- /dev/null +++ b/debian/debian13-init.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +# Runtime environment +source /etc/os-release +if [[ "${ID:-}" != "debian" || "${VERSION_ID:-}" != "13" ]]; then + echo "Error: this script supports Debian 13 only." >&2 + exit 1 +fi + +# Ensure interactive login shells can find system administration commands. +USR_SBIN_PROFILE=/etc/profile.d/usr-sbin-path.sh +if [[ ! -e "${USR_SBIN_PROFILE}" ]]; then + sudo tee "${USR_SBIN_PROFILE}" >/dev/null <<'EOF' +case ":${PATH}:" in + *:/usr/sbin:*) ;; + *) export PATH="${PATH}:/usr/sbin" ;; +esac +EOF + sudo chmod 0644 "${USR_SBIN_PROFILE}" + echo "Configured ${USR_SBIN_PROFILE}." +fi + +# Prevent /tmp from being mounted as a tmpfs +sudo systemctl mask tmp.mount + +# Window title bar buttons +gsettings set org.gnome.desktop.wm.preferences button-layout \ + ':minimize,maximize,close' + +# Show the weekday and seconds in the desktop clock +gsettings set org.gnome.desktop.interface clock-show-weekday true +gsettings set org.gnome.desktop.interface clock-show-seconds true + +# Set the idle timeout to 30 minutes +gsettings set org.gnome.desktop.session idle-delay 'uint32 1800' + +# Use touch-style scrolling direction for the mouse +gsettings set org.gnome.desktop.peripherals.mouse natural-scroll true + +# Disable Caps Lock +# gsettings set org.gnome.desktop.input-sources xkb-options "['caps:none']" +# Enable Caps Lock to toggle between keyboard layouts +gsettings set org.gnome.desktop.input-sources xkb-options "['grp:caps_toggle']" + +# Disable GNOME Software update checks, downloads, and notifications +gsettings set org.gnome.software allow-updates false +gsettings set org.gnome.software download-updates false +gsettings set org.gnome.software download-updates-notify false + +# Install Dash to Dock +sudo apt-get install -y gnome-shell-extension-dashtodock + +# Keep the Dash visible +gsettings set org.gnome.shell.extensions.dash-to-dock dock-fixed true +gsettings set org.gnome.shell.extensions.dash-to-dock autohide false +gsettings set org.gnome.shell.extensions.dash-to-dock intellihide false + +# Do not open the Activities Overview automatically after login +gsettings set org.gnome.shell.extensions.dash-to-dock \ + disable-overview-on-startup true + +# Dash click behavior +gsettings set org.gnome.shell.extensions.dash-to-dock click-action \ + 'focus-minimize-or-appspread' + +# Show one running indicator dot per application window +gsettings set org.gnome.shell.extensions.dash-to-dock \ + running-indicator-style 'DOTS' + +# Install AppIndicator +sudo apt-get install -y gnome-shell-extension-appindicator + +# Enable GNOME extensions +gsettings set org.gnome.shell enabled-extensions \ + "['dash-to-dock@micxgx.gmail.com', 'ubuntu-appindicators@ubuntu.com']" + +echo "GNOME desktop configuration completed. Log out and back in if a newly installed extension is not visible." diff --git a/macos/AGENTS.md b/macos/AGENTS.md new file mode 100644 index 0000000..49c4750 --- /dev/null +++ b/macos/AGENTS.md @@ -0,0 +1,90 @@ +# AGENTS.md + +## Project Overview + +This directory maintains a single shell script for initializing a newly set up +macOS user account. Except for this file, do not split functionality into +additional scripts, configuration generators, or other languages. Keep the +script flat, easy to review, and directly executable on the target machine, +in the same style as `../debian/debian13-init.sh`. + +## Scope + +This file applies to the `macos/` directory. The repository-level `AGENTS.md` +still applies; where the two conflict, this file takes precedence. + +## Development Principles + +- Write Bash and use `#!/usr/bin/env bash` as the first line. +- macOS ships bash 3.2 as `/bin/bash`. Do not use associative arrays, + `mapfile`, `${var,,}`, or other bash 4+ features. +- Keep the script flat: a short comment followed by the commands it explains, + with no helper functions unless repetition clearly demands one. +- Prefer `defaults write` for per-user preferences. Each write must be safe to + repeat. Use `-bool`, `-int`, or `-string` explicitly so the stored type is + stable. +- Double-quote variables, and use `"${HOME}"` rather than `~` inside strings. +- If a key only works on a specific macOS release, say so in a comment and + keep the version check in the script in sync. +- Comments should explain reasons, compatibility constraints, or risks rather + than restating each line of code. + +## Security Requirements + +- Never store passwords, tokens, private keys, or other sensitive information + in the repository, command-line arguments, or logs. +- Do not execute unverified remote content with patterns such as + `curl ... | sh` or `wget ... | bash`. This rules out the official Homebrew + installer; install it by hand if needed. +- Do not change SSH or Remote Login, the firewall, FileVault, Gatekeeper, + System Integrity Protection, networking, disks, boot configuration, or user + credentials without an explicit opt-in switch and a prominent warning. +- The script runs as the login user. Do not add `sudo`, and do not write + preferences into root's domain. + +## Behavior and Output + +- Check the OS and version first; fail with an actionable message on stderr + and a nonzero exit status. +- Restart only the apps whose preferences were changed, once, at the end. +- Features with significant impact or machine-specific behavior must be + disabled by default and run only when explicitly enabled. +- Mention in the final message anything that needs a logout or a restart to + take effect. + +## Change Constraints + +- Keep changes focused on macOS initialization. Do not add unrelated + functionality. +- Do not perform broad rewrites solely for style. Preserve existing behavior. +- Clearly state in the delivery notes when a change alters system behavior or + security policy. + +## Validation + +After modifying the script, run at least: + +```bash +bash -n ./*.sh +``` + +If ShellCheck is installed, also run: + +```bash +shellcheck ./*.sh +``` + +The development machine is usually the target machine. Unless explicitly +authorized by the user, do not run the script itself or `defaults write` on it +while testing; check a key with `defaults read` or `defaults read-type` +instead. List any behavior that could not be safely validated and recommend +running the script twice on a fresh macOS user account. + +## Delivery Notes + +When completing a change, briefly describe: + +- Which initialization behavior changed. +- Whether default behavior or system security policy changed. +- Which static checks or tests were run. +- Which operations still require validation on a fresh macOS user account. diff --git a/macos/macos-init.sh b/macos/macos-init.sh new file mode 100755 index 0000000..32d7dd4 --- /dev/null +++ b/macos/macos-init.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +# Runtime environment +if [[ "$(uname -s)" != "Darwin" ]]; then + echo "Error: this script supports macOS only." >&2 + exit 1 +fi +if (( $(sw_vers -productVersion | cut -d. -f1) < 13 )); then + echo "Error: this script requires macOS 13 or later." >&2 + exit 1 +fi + +# Show all file extensions in Finder +defaults write NSGlobalDomain AppleShowAllExtensions -bool true + +# Show the path bar and status bar in Finder +defaults write com.apple.finder ShowPathbar -bool true +defaults write com.apple.finder ShowStatusBar -bool true + +# Search the current folder by default, and use the list view +defaults write com.apple.finder FXDefaultSearchScope -string SCcf +defaults write com.apple.finder FXPreferredViewStyle -string Nlsv + +# Do not warn when changing a file extension +defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false + +# Keep .DS_Store files off network shares and USB drives +defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true +defaults write com.apple.desktopservices DSDontWriteUSBStores -bool true + +# Do not show recent applications in the Dock +defaults write com.apple.dock show-recents -bool false + +# Keep Spaces in a fixed order +defaults write com.apple.dock mru-spaces -bool false + +# Repeat keys instead of showing the accent popup, and repeat faster +defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false +defaults write NSGlobalDomain KeyRepeat -int 2 +defaults write NSGlobalDomain InitialKeyRepeat -int 25 + +# Tap to click +defaults write com.apple.AppleMultitouchTrackpad Clicking -bool true +defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true +defaults write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 + +# Expand the save and print dialogs by default +defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true +defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode2 -bool true +defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true +defaults write NSGlobalDomain PMPrintingExpandedStateForPrint2 -bool true + +# Save screenshots as PNG without window shadows to ~/Screenshots +mkdir -p "${HOME}/Screenshots" +defaults write com.apple.screencapture location -string "${HOME}/Screenshots" +defaults write com.apple.screencapture type -string png +defaults write com.apple.screencapture disable-shadow -bool true + +# Restart the affected apps so the settings above take effect +killall Finder Dock SystemUIServer >/dev/null 2>&1 || true + +echo "macOS configuration completed. Log out and back in if tap to click or key repeat does not take effect."