task install destroys/skips skill symlinks — use install.sh instead #7

Closed
opened 2026-07-03 22:26:40 +00:00 by mathias · 1 comment
Owner

Problem

The repo's task install (and targets like task install:claude:global) break the per-skill symlink wiring instead of establishing it. Observed 2026-07-04:

  • After task install: claude:0/40 crush:0/40 vibe:0/40 — every per-skill symlink gone.
  • A second task install:claude:global gave 22/40 (non-deterministic).
  • The identical link loop as plain bash, and install.sh, wire 40/40 every time (all four harnesses).

So the Taskfile installer is unreliable/destructive; install.sh is correct.

Likely cause

The multi-line - | install blocks mix Go-template {{.TASKFILE_DIR}}/{{.NON_SKILL_ENTRIES}} with shell $(...) and ${skill}. Suspects: task's default parallel execution of the install aggregate deps, or template/quoting of the regex. task list (single-line) works, so it's the multi-line-block handling, not TASKFILE_DIR resolution.

Repro

git clone https://git.d-ma.be/mathias/skills.git /tmp/skills && cd /tmp/skills
task install
for s in $(ls -1 | grep -Ev '^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md)$'); do [ -L ~/.claude/skills/$s ] && echo x; done | wc -l   # << 40
SKILLS_CHECKOUT_DIR="$PWD" bash install.sh   # now 40/40

Fix options

  1. Make task install delegate to install.sh (proven path) instead of reimplementing the loop — simplest, removes duplication.
  2. If keeping the loops: disable parallel deps, audit template/quoting, add a post-condition assert (links == skills).

Workaround (already documented)

install.sh — curl -fsSL .../install.sh | bash, or SKILLS_CHECKOUT_DIR="$PWD" bash install.sh. SKILLS_INDEX.md now points here.

Surfaced consolidating local-dev's embedded .skills/ into this repo (2026-07-04).

## Problem The repo's `task install` (and targets like `task install:claude:global`) break the per-skill symlink wiring instead of establishing it. Observed 2026-07-04: - After `task install`: `claude:0/40 crush:0/40 vibe:0/40` — every per-skill symlink gone. - A second `task install:claude:global` gave `22/40` (non-deterministic). - The identical link loop as plain bash, and `install.sh`, wire `40/40` every time (all four harnesses). So the Taskfile installer is unreliable/destructive; `install.sh` is correct. ## Likely cause The multi-line `- |` install blocks mix Go-template `{{.TASKFILE_DIR}}`/`{{.NON_SKILL_ENTRIES}}` with shell `$(...)` and `${skill}`. Suspects: task's default parallel execution of the `install` aggregate deps, or template/quoting of the regex. `task list` (single-line) works, so it's the multi-line-block handling, not TASKFILE_DIR resolution. ## Repro git clone https://git.d-ma.be/mathias/skills.git /tmp/skills && cd /tmp/skills task install for s in $(ls -1 | grep -Ev '^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md)$'); do [ -L ~/.claude/skills/$s ] && echo x; done | wc -l # << 40 SKILLS_CHECKOUT_DIR="$PWD" bash install.sh # now 40/40 ## Fix options 1. Make `task install` delegate to `install.sh` (proven path) instead of reimplementing the loop — simplest, removes duplication. 2. If keeping the loops: disable parallel deps, audit template/quoting, add a post-condition assert (links == skills). ## Workaround (already documented) `install.sh` — `curl -fsSL .../install.sh | bash`, or `SKILLS_CHECKOUT_DIR="$PWD" bash install.sh`. SKILLS_INDEX.md now points here. Surfaced consolidating local-dev's embedded `.skills/` into this repo (2026-07-04).
mathias added the risk/mediumsize/stype/fix labels 2026-08-27 05:25:45 +00:00
Author
Owner

Already fixed — closing on live verification rather than on a new change.

Fix option 1 from this issue is what the repo does today. Taskfile.yml:

  install:
    desc: 'Wire THIS checkout into Crush / Pi / OpenCode. Claude Code uses the plugin instead.'
    cmds:
      - SKILLS_SKIP_FETCH=1 SKILLS_CHECKOUT_DIR='{{.TASKFILE_DIR}}' bash '{{.TASKFILE_DIR}}/install.sh'

The file's own header records why: "The wiring loops that used to live here were five near-identical copies that drifted; install.sh owns wiring now and this file delegates to it." No multi-line - | block, no template/shell mixing, no parallel aggregate deps — so the mechanism this issue suspected is gone rather than patched.

Verified on koala just now:

$ task install
[skills] using /home/mathias/dev/skills as-is (SKILLS_SKIP_FETCH=1)
[skills] done — 42 skill(s) at ref=main, 3 links total
INSTALL_EXIT=0

$ task doctor
skills doctor: clean — 42 skills, checkout /home/mathias/dev/skills
DOCTOR_EXIT=0

The repro in the issue body no longer applies as written, for a second reason worth noting: the count it asserts (per-skill links in ~/.claude/skills/, 40 of them) is no longer the target shape at all. Wiring is now one directory symlink per harness — ~/.agents/skills → the checkout, with crush and opencode pointing at that link — and Claude Code goes through the plugin, not symlinks. Per-skill links in ~/.claude/skills/ are now a fault, reported by task doctor.

So "0/40" today would mean correct, not broken. Anyone re-testing this should assert on task doctor exiting 0, which is the check that survived the layout change.

Already fixed — closing on live verification rather than on a new change. Fix option 1 from this issue is what the repo does today. `Taskfile.yml`: ```yaml install: desc: 'Wire THIS checkout into Crush / Pi / OpenCode. Claude Code uses the plugin instead.' cmds: - SKILLS_SKIP_FETCH=1 SKILLS_CHECKOUT_DIR='{{.TASKFILE_DIR}}' bash '{{.TASKFILE_DIR}}/install.sh' ``` The file's own header records why: *"The wiring loops that used to live here were five near-identical copies that drifted; install.sh owns wiring now and this file delegates to it."* No multi-line `- |` block, no template/shell mixing, no parallel aggregate deps — so the mechanism this issue suspected is gone rather than patched. Verified on koala just now: ``` $ task install [skills] using /home/mathias/dev/skills as-is (SKILLS_SKIP_FETCH=1) [skills] done — 42 skill(s) at ref=main, 3 links total INSTALL_EXIT=0 $ task doctor skills doctor: clean — 42 skills, checkout /home/mathias/dev/skills DOCTOR_EXIT=0 ``` The repro in the issue body no longer applies as written, for a second reason worth noting: the count it asserts (per-skill links in `~/.claude/skills/`, 40 of them) is no longer the target shape at all. Wiring is now **one directory symlink per harness** — `~/.agents/skills` → the checkout, with crush and opencode pointing at that link — and Claude Code goes through the plugin, not symlinks. Per-skill links in `~/.claude/skills/` are now a *fault*, reported by `task doctor`. So "0/40" today would mean correct, not broken. Anyone re-testing this should assert on `task doctor` exiting 0, which is the check that survived the layout change.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/skills#7