Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions .claude/rules/cross-platform.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ These rules apply to all agents and all sessions.

- **macOS** (primary environment, frequently used)
- **EndeavourOS / Arch Linux** (also used)
- **Debian** (stable, trixie / 13+ — all servers run Debian)

## Separation principle

macOS and Arch must be **considered separately** for every decision that could differ between them.
macOS, Arch, and Debian must be **considered separately** for every decision that could differ between them.

Do not assume a single approach works on both without explicit analysis.
Do not assume a single approach works on all three without explicit analysis.

## Package manager rules

- Do not assume **Homebrew** exists on Arch.
- Do not assume **pacman** or **yay** exists on macOS.
- Do not mix macOS package manager commands into Arch documentation, or vice versa.
- Do not assume **Homebrew** exists on Arch or Debian.
- Do not assume **pacman** or **yay** exists on macOS or Debian.
- Do not assume **apt** exists on macOS or Arch.
- Do not mix one platform's package manager commands into another's documentation.
- When suggesting package installation, specify the target platform:

```
Expand All @@ -26,13 +28,21 @@ Do not assume a single approach works on both without explicit analysis.

# Arch / EndeavourOS
sudo pacman -S <package>

# Debian
sudo apt install <package>
```

- Debian binary-name quirks: `bat` runs as `batcat`, `fd` ships in `fd-find`
and runs as `fdfind`. `go-task` and `oh-my-posh` are not in the Debian
archive — install them out-of-band (see `packages/debian/packages.txt`).

## Configuration separation

- **Common packages**: configurations that work on both platforms without modification.
- **Common packages**: configurations that work on all platforms without modification.
- **macOS-specific packages**: configurations only applicable to macOS.
- **Arch-specific packages**: configurations only applicable to EndeavourOS / Arch.
- **Debian-specific packages**: configurations only applicable to Debian.
- Do not mix OS-specific settings into common/shared config files.

## Script safety
Expand All @@ -45,12 +55,16 @@ Do not assume a single approach works on both without explicit analysis.
# macOS
elif [[ -f /etc/arch-release ]]; then
# Arch / EndeavourOS
elif [[ -f /etc/debian_version ]]; then
# Debian
else
echo "Unsupported OS"
exit 1
fi
```

Order matters: test `/etc/arch-release` before `/etc/debian_version`.

## Path safety

- Avoid hardcoded machine-specific paths (e.g., `/Users/yourusername/` or `/home/yourusername/`).
Expand All @@ -62,5 +76,5 @@ Do not assume a single approach works on both without explicit analysis.
When documenting any command or config, always state which platform it applies to if it is not portable.

Convention for inline platform labels:
- In code blocks: use `# macOS` or `# Arch` comments on the first line.
- In prose: use `[macOS]` or `[Arch]` labels before the relevant item.
- In code blocks: use `# macOS`, `# Arch`, or `# Debian` comments on the first line.
- In prose: use `[macOS]`, `[Arch]`, or `[Debian]` labels before the relevant item.
21 changes: 12 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Key context:

- **macOS** is frequently used (primary environment).
- **EndeavourOS / Arch Linux** is also used.
- **Debian** (stable, trixie / 13+) runs on all servers.
- **GNU Stow** is the symlink manager (package-based layout under `stow/`).
- Dotfiles are **stowed** — all `stow/common/` packages are symlinked into `$HOME`.
- The Claude Code operating layer (agents, rules, skills, documentation workflow) is complete and active.
Expand All @@ -23,7 +24,7 @@ Key context:
```
Current status: Claude Code operating layer complete; common packages stowed.
Dotfiles implementation: stowed — all stow/common/ packages symlinked into $HOME.
GNU Stow packages: see stow/common/ (source of truth; macos/ and arch/ empty).
GNU Stow packages: see stow/common/ (source of truth; macos/, arch/, debian/ empty).
Stowed to $HOME: all stow/common/ packages — live symlinks into the repo.
Home directory: modified by these symlinks; further modifications forbidden unless explicitly requested.
```
Expand All @@ -41,7 +42,7 @@ Home directory: modified by these symlinks; further modifications forbi
5. **Planning before building** — approved plan required before any implementation.
6. **Review before committing** — Reviewer validates every change before commit.
7. **Incremental adoption** — add dotfiles one package at a time, never all at once.
8. **Cross-platform by design** — macOS and Arch are treated separately from the start.
8. **Cross-platform by design** — macOS, Arch, and Debian are treated separately from the start.
9. **No destructive automation** — risky commands are shown, not executed.

---
Expand All @@ -54,8 +55,8 @@ Home directory: modified by these symlinks; further modifications forbi

- Define repository structure and layout.
- Make architecture decisions and document tradeoffs.
- Consider long-term maintainability across macOS and Arch.
- Consider macOS and Arch **separately** — never assume a shared approach.
- Consider long-term maintainability across macOS, Arch, and Debian.
- Consider macOS, Arch, and Debian **separately** — never assume a shared approach.
- Define risks and open questions.
- Avoid implementation unless explicitly asked.

Expand Down Expand Up @@ -166,7 +167,7 @@ Home directory: modified by these symlinks; further modifications forbi

- Review changes for **safety** — no destructive operations introduced.
- Review changes for **privacy** — no secrets, tokens, keys, or sensitive data.
- Review **cross-platform correctness** — macOS and Arch not incorrectly mixed.
- Review **cross-platform correctness** — macOS, Arch, and Debian not incorrectly mixed.
- Review **documentation clarity** — commands are copy-pasteable and safe.
- Check that examples use placeholder values, not real data.
- Verify no `stow --adopt`, `rm`, `mv`, or `ln -s` targeting `$HOME` was introduced.
Expand Down Expand Up @@ -313,16 +314,18 @@ docs/claude/ → agent guides and workflow documentation

## 10. Cross-Platform Rules

- macOS and EndeavourOS / Arch must be **considered separately**.
- Do not use Homebrew commands in Arch configs.
- Do not use pacman or yay commands in macOS configs.
- macOS, EndeavourOS / Arch, and Debian must be **considered separately**.
- Do not use Homebrew commands in Arch or Debian configs.
- Do not use pacman or yay commands in macOS or Debian configs.
- Do not use apt commands in macOS or Arch configs.
- Do not mix OS-specific config into shared/common config.
- Commands must **specify the target OS** when relevant.
- Future scripts must **detect OS** before suggesting package manager commands.
- Avoid hardcoded machine-specific paths.
- Common packages: configurations that work on both platforms without modification.
- Common packages: configurations that work on all platforms without modification.
- macOS-specific: configurations only for macOS.
- Arch-specific: configurations only for EndeavourOS / Arch.
- Debian-specific: configurations only for Debian.

---

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Read `AGENTS.md` first.
Current repository status:

- Claude Code operating layer complete.
- GNU Stow packages live under `stow/common/` (source of truth; `macos/` and `arch/` empty). Real config, plus some `.example` templates for local-only files.
- GNU Stow packages live under `stow/common/` (source of truth; `macos/`, `arch/`, `debian/` empty). Real config, plus some `.example` templates for local-only files.
- All `stow/common/` packages are stowed to `$HOME` (live symlinks into the repo). Home directory is modified by these symlinks. `stow/common/` remains the source of truth for which packages exist.
- Home directory modifications are forbidden unless explicitly requested.

Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
<a href="https://fnayou.github.io/dotfiles/">Documentation</a>
</p>

Private, safe, cross-platform personal dotfiles for **macOS** and **EndeavourOS / Arch Linux**,
managed with [GNU Stow](https://www.gnu.org/software/stow/).
Private, safe, cross-platform personal dotfiles for **macOS**, **EndeavourOS / Arch Linux**, and
**Debian** (trixie / 13+), managed with [GNU Stow](https://www.gnu.org/software/stow/).

macOS is the primary environment; Arch is supported from the start. Configs are version-controlled
macOS is the primary environment; Arch is supported from the start, and Debian runs on all servers.
Configs are version-controlled
in `stow/common/` and only ever symlinked into `$HOME` by a **deliberate, manual** Stow step —
never automatically.

Expand All @@ -29,8 +30,8 @@ live symlinks point from `$HOME` into the repo. Stow is still always a deliberat

## What's included

Each package is self-contained and carries its own README. `stow/macos/` and `stow/arch/` are
reserved for platform-specific packages and are currently empty.
Each package is self-contained and carries its own README. `stow/macos/`, `stow/arch/`, and
`stow/debian/` are reserved for platform-specific packages and are currently empty.

| Package | What it manages | Details | Guide |
|---|---|---|---|
Expand Down Expand Up @@ -95,9 +96,10 @@ approval and an approved plan.
```
.claude/ Claude Code agents, rules, and skills
stow/
common/ Packages that work on both platforms (source of truth)
common/ Packages that work on all platforms (source of truth)
macos/ macOS-specific packages (empty)
arch/ Arch / EndeavourOS-specific packages (empty)
debian/ Debian-specific packages (empty)
docs/
guides/ Human setup guides, one per package
architecture/ Structure decisions and tradeoffs
Expand Down
48 changes: 48 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,54 @@ tasks:
echo " task deps:check:zsh"
echo ""

deps:debian:
desc: "Print manual install commands for Debian (stable / trixie) — prints only, does not install"
silent: true
cmds:
- |
echo ""
echo "Shell dependency install commands (Debian stable / trixie)"
echo "=========================================================="
echo ""
echo "Step 1 — Install apt packages:"
echo ""
echo " ⚠️ MANUAL STEP — review before running"
echo " sudo apt install git stow fzf zoxide eza bat \\"
echo " neovim ripgrep fd-find nodejs npm python3 python3-pip pipx build-essential"
echo ""
echo " Note — Debian binary names differ: bat -> batcat, fd -> fdfind"
echo ""
echo " Note — Neovim version: nvim-treesitter (main) needs Neovim >= 0.11."
echo " If apt's neovim is older (check: nvim --version), use the prebuilt tarball:"
echo " curl -fsSL https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz \\"
echo " | tar xz -C ~/.local --strip-components=1"
echo ""
echo "Step 2 — Out-of-band tools (not in the Debian archive):"
echo ""
echo " ⚠️ MANUAL STEP — review before running"
echo " sh -c \"\$(curl -fsSL https://taskfile.dev/install.sh)\" -- -d -b ~/.local/bin # go-task"
echo " curl -s https://ohmyposh.dev/install.sh | bash -s # oh-my-posh"
echo ""
echo "Step 3 — Install zinit (one-time manual clone):"
echo ""
echo " ⚠️ MANUAL STEP — review before running"
echo " git clone https://github.com/zdharma-continuum/zinit.git \\"
echo " \"\${XDG_DATA_HOME:-\$HOME/.local/share}/zinit/zinit.git\""
echo ""
echo "Step 4 — tree-sitter CLI (node-free prebuilt binary, not npm):"
echo ""
echo " ⚠️ MANUAL STEP — review before running"
echo " curl -fsSL https://github.com/tree-sitter/tree-sitter/releases/latest/download/tree-sitter-linux-x64.gz \\"
echo " | gunzip > ~/.local/bin/tree-sitter && chmod +x ~/.local/bin/tree-sitter"
echo ""
echo " Then launch Neovim once to install plugins + LSP servers:"
echo " nvim --headless \"+Lazy! sync\" +qa"
echo ""
echo "Step 5 — Verify:"
echo ""
echo " task deps:check:zsh"
echo ""

git:bootstrap:dry-run:
desc: "Show include.path entries that would be added to ~/.gitconfig — no changes made. MANUAL USE ONLY: never run automatically"
silent: true
Expand Down
88 changes: 88 additions & 0 deletions docs/decisions/0053-debian-added-as-third-supported-platform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# 0053 — Debian added as a third supported platform

- Status: Accepted
- Date: 2026-06-29

## Context

Until now the repository supported exactly two platforms, treated separately
per the cross-platform rule: **macOS** (primary) and **EndeavourOS / Arch
Linux**. All servers the maintainer runs are **Debian** (stable, currently
trixie / Debian 13), and Neovim is used on them directly.

A concrete failure surfaced this gap. `nvim-treesitter` is pinned to its
`main` branch (`stow/common/nvim/.config/nvim/init.lua`), which builds parsers
by shelling out to a `tree-sitter` CLI binary. A Debian server had no
`tree-sitter` CLI, so parser builds failed with:

```
ENOENT ... (cmd): 'tree-sitter'
```

The repository's documented remedy was node-specific
(`npm install -g tree-sitter-cli`). On that server there was no `node` at all,
so the documented path did not apply. The fix used a prebuilt static
`tree-sitter` binary instead.

This exposed two things:

1. Debian is a real, recurring target, not an incidental "unknown" OS.
2. The tree-sitter CLI install advice assumed node was present.

## Decision

1. **Debian becomes a first-class supported platform**, alongside macOS and
Arch. The cross-platform rule, agent contract (`AGENTS.md`), status blocks,
dependency scripts, package manifests, task runner, and human setup guides
all treat Debian explicitly and separately — never folded into Arch or
assumed to share an approach.

2. **Package manager on Debian is `apt`.** Debian uses `sudo apt install`.
Arch's `pacman`/`yay` and macOS's `brew` are never mixed into Debian docs,
and vice versa.

3. **tree-sitter CLI on Debian is installed from the prebuilt GitHub release
binary**, not via npm:

```bash
curl -fsSL https://github.com/tree-sitter/tree-sitter/releases/latest/download/tree-sitter-linux-x64.gz \
| gunzip > ~/.local/bin/tree-sitter && chmod +x ~/.local/bin/tree-sitter
```

Rationale: it is node-free, version-pinnable, and avoids ABI drift between
a node wrapper and Neovim's runtime. `apt`'s `tree-sitter-cli` exists but
trails upstream (0.22.x on trixie) and needs sudo.

4. **node is still installed on Debian hosts** (`nodejs`, `npm`) so that
Mason-installed LSP servers work, even though tree-sitter itself no longer
depends on it.

## Consequences

- New file `packages/debian/packages.txt` lists apt packages, mirroring
`packages/arch/packages.txt`.
- New `deps:debian` task prints (never runs) the Debian install commands.
- `scripts/check-nvim-deps.sh` and `scripts/check-zsh-deps.sh` detect Debian
(`/etc/debian_version`) and print apt-flavoured hints.
- An empty `stow/debian/` package directory exists for parity with
`stow/macos/` and `stow/arch/`; no Debian-only packages exist yet.
- Status blocks in `AGENTS.md` and `CLAUDE.md` now name macOS, Arch, and
Debian, and report `macos/`, `arch/`, `debian/` as empty.
- Debian quirks are documented where relevant: `bat` ships as `batcat`,
`fd` as `fdfind` (package `fd-find`); `go-task` and `oh-my-posh` are not in
the Debian archive and are installed out-of-band.
- **Neovim version risk:** nvim-treesitter's `main` branch needs Neovim
>= 0.11. Debian stable's apt `neovim` may be older. The package list, task,
and guides document a node-free prebuilt-tarball fallback into `~/.local`
for when apt's neovim is too old. (`eza` is likewise apt-available only on
trixie/13+, not bookworm/12 — hence the trixie/13+ scope.)
- Homebrew/linuxbrew was considered for Debian (one shared Brewfile with
macOS, always-latest versions) but rejected to keep servers apt-native and
minimal — no `/home/linuxbrew` layer. apt is the Debian package manager;
curl-prebuilt covers the two tools apt can't serve well (tree-sitter CLI
always, neovim when too old).

## Related

- `.claude/rules/cross-platform.md` — platform separation contract.
- `0048-status-blocks-kept-in-sync-with-repo-state.md` — status-block sync.
Loading
Loading