Fold dotfiles-nixos into this repository #1

Merged
alexion merged 32 commits from nixos-migration into main 2026-07-19 09:30:46 -04:00
4 changed files with 20 additions and 6 deletions
Showing only changes of commit 7809e079e3 - Show all commits

View File

@@ -40,6 +40,10 @@ The domain model (Host, Module, Skeleton, Auto-loader, Enable convention, overla
- The remote is self-hosted Gitea (`git.alexion.dev`), driven with `gitea-axi` rather than `tea`; `gh` is not installed. - The remote is self-hosted Gitea (`git.alexion.dev`), driven with `gitea-axi` rather than `tea`; `gh` is not installed.
`gitea-axi` resolves the repository from the `origin` remote and takes credentials from the `axi` tea login, so both are implicit inside a checkout. `gitea-axi` resolves the repository from the `origin` remote and takes credentials from the `axi` tea login, so both are implicit inside a checkout.
`tea` remains installed only as that credential source. `tea` remains installed only as that credential source.
- `~/.claude/skills` is generated by home-manager with `recursive = true`, so the directories are real and writable but every leaf file is a read-only symlink into the store.
Editing a skill in place fails; its source is `modules/claude-code/skills/<name>/` here, applied by a rebuild.
Creating a new file under `~/.claude/skills/` succeeds silently and is the trap — it stays outside the repo and reaches no other machine.
Copying out of that tree needs `cp -rL` plus `chmod -R u+w`: a plain `cp -r` copies the symlinks, putting store paths into the destination, and dereferenced files keep the store's read-only mode.
- nixpkgs `vimPlugins.nord-nvim` is `shaunsingh/nord.nvim` (no `require("nord").setup()`); the config wants `gbprod/nord.nvim`, which is packaged as `vimPlugins.gbprod-nord`. - nixpkgs `vimPlugins.nord-nvim` is `shaunsingh/nord.nvim` (no `require("nord").setup()`); the config wants `gbprod/nord.nvim`, which is packaged as `vimPlugins.gbprod-nord`.
- nixpkgs `vimPlugins.nvim-treesitter` tracks the rewritten `main` branch: there is no `require("nvim-treesitter.configs").setup{ensure_installed,highlight,indent}`. Under nixvim, use `plugins.treesitter` with `highlight.enable`/`indent.enable` and `grammarPackages = with config.programs.nixvim.plugins.treesitter.package.builtGrammars; [ ... ]` — the module's own `package.builtGrammars`, **not** `pkgs.vimPlugins.nvim-treesitter.*` (whose query files can mismatch). The module targets the main branch and enables features via neovim-native APIs (`vim.treesitter.start()`, `require'nvim-treesitter'.indentexpr()`). - nixpkgs `vimPlugins.nvim-treesitter` tracks the rewritten `main` branch: there is no `require("nvim-treesitter.configs").setup{ensure_installed,highlight,indent}`. Under nixvim, use `plugins.treesitter` with `highlight.enable`/`indent.enable` and `grammarPackages = with config.programs.nixvim.plugins.treesitter.package.builtGrammars; [ ... ]` — the module's own `package.builtGrammars`, **not** `pkgs.vimPlugins.nvim-treesitter.*` (whose query files can mismatch). The module targets the main branch and enables features via neovim-native APIs (`vim.treesitter.start()`, `require'nvim-treesitter'.indentexpr()`).
- Neovim is configured via **nixvim** (flake input `nixvim`, consumed as `inputs.nixvim.homeModules.nixvim` added to `home-manager.sharedModules`, config under `home-manager.users.<user>.programs.nixvim`). `nixvim.inputs.nixpkgs.follows = "nixpkgs"` is set; nixvim then emits a benign eval warning that its pinned nixpkgs differs from the followed one — builds and runs fine, do not "fix" it by dropping the follows. - Neovim is configured via **nixvim** (flake input `nixvim`, consumed as `inputs.nixvim.homeModules.nixvim` added to `home-manager.sharedModules`, config under `home-manager.users.<user>.programs.nixvim`). `nixvim.inputs.nixpkgs.follows = "nixpkgs"` is set; nixvim then emits a benign eval warning that its pinned nixpkgs differs from the followed one — builds and runs fine, do not "fix" it by dropping the follows.

View File

@@ -23,11 +23,11 @@ If the request describes a new workflow, capability, or repeated manual process
- Is there already a word — in your prompts, docs, or codebase — that names this behavior? Reach for that **leading word** before coining one. - Is there already a word — in your prompts, docs, or codebase — that names this behavior? Reach for that **leading word** before coining one.
Done when every axis above has an answer, or the user says to just draft something and iterate. Done when every axis above has an answer, or the user says to just draft something and iterate.
2. **Write the draft.** First decide where it lives: project-local `.claude/skills/` if the workflow is tied to this one repo, `~/.claude/skills/` if it's general-purpose across projects. Then follow the **information hierarchy**: steps for what the agent does in order, in-file **reference** for facts every branch needs, and disclose the rest behind a pointer — to a sibling file, or to the existing project docs identified in step 1 rather than restating them. Done when every branch from step 1 has somewhere to live, and no sentence fails the no-op test in isolation (see `No-Op` in GLOSSARY.md). 2. **Write the draft.** First decide where it lives: project-local `.claude/skills/` if the workflow is tied to this one repo, the personal set if it's general-purpose across projects. The personal set is not authored in `~/.claude/skills/` — that tree is generated, and every file under it is a read-only symlink into the Nix store. Write it in the dotfiles repo at `modules/claude-code/skills/<name>/` and rebuild to make it live. Creating files directly under `~/.claude/skills/` looks like it works, because the directories themselves are writable, but the result is untracked by the repo and reaches no other machine. Then follow the **information hierarchy**: steps for what the agent does in order, in-file **reference** for facts every branch needs, and disclose the rest behind a pointer — to a sibling file, or to the existing project docs identified in step 1 rather than restating them. Done when every branch from step 1 has somewhere to live, and no sentence fails the no-op test in isolation (see `No-Op` in GLOSSARY.md).
## Audit an existing skill ## Audit an existing skill
1. **Locate it.** Check the current project's `.claude/skills/`, then `~/.claude/skills/`, then `~/.claude/skills/library/`, in that order; ask if the name is ambiguous across locations. If it's tracked in a project's `skills-lock.yaml`, mention that editing it here will make it read as locally-customized to `update-skills` — confirm that's actually intended rather than editing the library source. 1. **Locate it.** Check the current project's `.claude/skills/`, then `~/.claude/skills/`, then `~/.claude/skills/library/`, in that order; ask if the name is ambiguous across locations. A hit under `~/.claude/skills/` is a read-only symlink and cannot be edited in place: its source is the dotfiles repo, at `modules/claude-code/skills/<name>/` for a personal skill or `modules/claude-code/skills/library/<name>/` for a library one. Edit there and rebuild. If it's tracked in a project's `skills-lock.yaml`, mention that editing it here will make it read as locally-customized to `update-skills` — confirm that's actually intended rather than editing the library source.
2. **Apply the checklist.** Read the skill and its disclosed files, then check each against GLOSSARY.md, quoting the offending line for anything that fails: 2. **Apply the checklist.** Read the skill and its disclosed files, then check each against GLOSSARY.md, quoting the offending line for anything that fails:
- **Premature completion** — is each completion criterion checkable, and does it demand what the step actually needs? - **Premature completion** — is each completion criterion checkable, and does it demand what the step actually needs?
@@ -44,6 +44,6 @@ If the request describes a new workflow, capability, or repeated manual process
1. Propose one realistic test prompt — reflecting the trigger phrasing gathered (draft) or the skill's existing purpose (audit) — and get it confirmed or adjusted before spending a run on it. 1. Propose one realistic test prompt — reflecting the trigger phrasing gathered (draft) or the skill's existing purpose (audit) — and get it confirmed or adjusted before spending a run on it.
2. Spawn one subagent: give it the skill's path and the confirmed prompt, have it attempt the task using the skill, and report back what happened — including anywhere it hesitated, misread the skill, or did something unexpected. 2. Spawn one subagent: give it the skill's path and the confirmed prompt, have it attempt the task using the skill, and report back what happened — including anywhere it hesitated, misread the skill, or did something unexpected.
3. Re-read the draft/rewrite against GLOSSARY.md's failure modes in light of that run, and fix whatever either pass turned up. If the fix is substantial, repeat from step 1; otherwise it's done. 3. Re-read the draft/rewrite against GLOSSARY.md's failure modes in light of that run, and fix whatever either pass turned up. If the fix is substantial, repeat from step 1; otherwise it's done.
4. Stage the specific changed or created paths — one path per file, never a wildcard — with the host project's own staging convention: plain `git add <path>` normally, or e.g. `dot add <path>` in this dotfiles setup (wrap as `fish -c "dot add <path>"` if the invoking shell isn't fish — `dot` is a fish function, not a binary on `$PATH`). Do not commit; that's left to the user. 4. Stage the specific changed or created paths — one path per file, never a wildcard — with `git add <path>`. Do not commit; that's left to the user.
Done when the subagent's run succeeded without confusion on the confirmed prompt, the checklist raised nothing outstanding, and every changed path is staged. Done when the subagent's run succeeded without confusion on the confirmed prompt, the checklist raised nothing outstanding, and every changed path is staged.

View File

@@ -10,6 +10,12 @@ the current project's `.claude/skills/`, tracked in
Only ever adds — checking already-installed skills for updates is Only ever adds — checking already-installed skills for updates is
[`update-skills`](../update-skills/SKILL.md)'s job, not this one's. [`update-skills`](../update-skills/SKILL.md)'s job, not this one's.
The library is a tree of read-only symlinks into the Nix store, so every
copy out of it must dereference (`cp -rL`) and then restore write
permission (`chmod -R u+w`). A plain `cp -r` copies the symlinks
themselves, putting store paths into the project that break on any other
machine.
## Steps ## Steps
1. Read `.claude/skills-lock.yaml` in the current project, if it exists. 1. Read `.claude/skills-lock.yaml` in the current project, if it exists.
@@ -35,7 +41,8 @@ Only ever adds — checking already-installed skills for updates is
skill already lives there and isn't tracked — remove or rename it skill already lives there and isn't tracked — remove or rename it
first if they want the library version). first if they want the library version).
- Otherwise, copy `~/.claude/skills/library/<name>/` to - Otherwise, copy `~/.claude/skills/library/<name>/` to
`.claude/skills/<name>/` in the project, run `.claude/skills/<name>/` in the project with
`cp -rL` followed by `chmod -R u+w`, run
`~/.claude/skills/setup-skills/hash-dir.sh .claude/skills/<name>`, `~/.claude/skills/setup-skills/hash-dir.sh .claude/skills/<name>`,
and append `{name, hash: <output>}` to `.claude/skills-lock.yaml` and append `{name, hash: <output>}` to `.claude/skills-lock.yaml`
(create the file, an empty YAML list, if it doesn't exist yet). (create the file, an empty YAML list, if it doesn't exist yet).

View File

@@ -36,8 +36,11 @@ skill that isn't already there — that's
already included an explicit go-ahead argument (e.g. `-y`, `yes`), in already included an explicit go-ahead argument (e.g. `-y`, `yes`), in
which case apply them without asking. Applying means: delete which case apply them without asking. Applying means: delete
`.claude/skills/<name>/` entirely and copy `.claude/skills/<name>/` entirely and copy
`~/.claude/skills/library/<name>/` in its place, so no file the project `~/.claude/skills/library/<name>/` in its place with `cp -rL` followed
copy had but the library no longer has can survive — then recompute its by `chmod -R u+w` (the library is read-only symlinks into the Nix store;
a plain `cp -r` would put store paths into the project), so no file the
project copy had but the library no longer has can survive — then
recompute its
hash and overwrite that entry's `hash` in `.claude/skills-lock.yaml` in hash and overwrite that entry's `hash` in `.claude/skills-lock.yaml` in
place. place.