# Higgsfield Pack Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use subagent-driven-development to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** `make plugin` installs the Higgsfield CLI and its skills, off by default, with two toggles to turn them on. **Architecture:** A sourced helper (`lib/higgsfield-skills.sh`) clones the upstream skills into gitignored `skills-external/higgsfield-*` and probes the CLI; both installers and the doctor call it. `lib/toggle-external.sh` links the skills on demand through two tools: `higgsfield`, a fixed allowlist of seven media skills, and `higgsfield-websites`, a single skill. Nothing is listed in `link.sh` or in a profile, which is what keeps the pack off across re-runs. **Tech Stack:** bash, git, npm (run by the user only), shellcheck, hermetic suites under `lib/tests/` run through `make test`. **Spec:** `docs/superpowers/specs/2026-09-30-higgsfield-pack-design.md` **Contract:** `.claude/tasks/contracts/2026-09-30-higgsfield-pack-1412.md` (14 criteria, binding) ## How this plan is packaged Every edit below was dry-run in a scratch copy, task by task, in order. The suite went 0/5 → 5/0 (Task 2), 6/8 → 14/0 (Task 3), 14/1 → 15/0 (Task 4), 15/1 → 16/0 (Task 5); shellcheck is clean; each patch applies to the branch; four deliberate bugs injected in the scratch code turned the suite red. The hardened clone was tried against a missing GitHub repo from a VS Code terminal (askpass exported): it failed at once, with no prompt. The exact bytes live in `docs/superpowers/plans/2026-09-30-higgsfield-pack.patches/`. Each task shows its code inline for reading and names the file to apply. Apply the file, never a retyped copy. Apply a patch with `git apply `. If `git apply` refuses (the target moved), stop and report `BLOCKED` with the error. Do not hand-merge. ## Global Constraints - Executors never run `install-plugins.sh`, `update-all.sh`, `link.sh`, `doctor.sh`, `npm install`, `npx`, `lib/toggle-external.sh` against the real repo, or `higgsfield_sync_skills` against the network (BDR-095). The suite is the only thing that runs. - Tests run through `make test suite=lib/tests/` only. Never call a suite with `bash` directly, never prefix the command with env variables. - Nothing about Higgsfield goes in `link.sh`, `lib/profile.sh`, `lib/profiles/*.profile` or `lib/effort-pins.txt` (BDR-093, BDR-079, BDR-105, BDR-107). The suite locks this. - The skill sync sits before the last `apply_effort_pins "$REPO"` in `install-plugins.sh` and `update-all.sh` (BDR-108, BLK-024). - `lib/toggle-external.sh` takes no new top-level `source` (LRN-178). - The CLI token never reaches a terminal or a log: `higgsfield auth token` is only ever called through `_higgsfield_probe` (helper) or `bounded` (toggle), both of which redirect to `/dev/null`. - CLI presence is proven by `higgsfield_cli_ok` (the binary answers), never by `command -v higgsfield` alone: the npm shim can sit on PATH with no binary behind it. - Media pack membership is the allowlist `HIGGSFIELD_MEDIA_SKILLS`, never a glob: upstream is unpinned, and an unlisted skill must stay unlinked (default deny). - House limits for new code: functions of 25 logic lines at most, 5 parameters, 5 locals; logic lines within 80 columns (message strings on `ok | info | warn | err | echo | printf` lines and the existing long `case` patterns follow the surrounding installer style and may run longer); shellcheck clean; comments state intent. - Commits: explicit paths only (`git add `), never `git add -A`, never `--no-verify`, no attribution trailer. The hooks push each commit. - `CLAUDE.global.md` and `settings.json` are hand-curated (BDR-028): only the orchestrator touches them. ## Review Focus 1. A refresh while the pack is enabled: the live `skills/` link must keep resolving. Pinned by `live-reads` in `SYNC_KEEPS_PARKED` (Task 2). 2. Upstream changes its layout (no `higgsfield-*/SKILL.md`, a pack-named dir without SKILL.md, a pack-named symlink): the sync must skip what is not a real skill directory, and return non-zero with the copies kept when nothing qualifies. Pinned by `noskill`, `symlink` and `no-skills` (Task 2). 3. Upstream adds or renames a skill: it is synced, reported, and never linked by `enable higgsfield`. Pinned by `UNLISTED_NOT_LINKED` (Task 3). 4. npm holds back the package's postinstall script, on a first install or on a later update, so the shim exists and the binary does not. `higgsfield_cli_ok` must say no (`shim-only` in `PROBES_SILENT`, Task 2), the toggle must name that cause and not "sign in" (`shim-*` in `SIGNED_OUT_WARNS`, Task 3), and both installers must gate on the probe (`probe-gates`, `probe-after-npm`, Tasks 4 and 5). The installer branches themselves cannot run in a suite: checked by reading. 5. The generalised pack arms must not change what `21st` prints or does. Pinned by `PACK_21ST_UNCHANGED` (Task 3). ## Rollback Before reverting these commits on a machine where the pack was enabled, run `bash lib/toggle-external.sh disable higgsfield` and `disable higgsfield-websites`. Otherwise the live `skills/higgsfield-*` links outlive the toggle that knows them and the gitignore rule that hides them. Reverting Task 1 also stops ignoring the synced `skills-external/higgsfield-*` sources: they show up as untracked until the user removes those directories by hand. ## Known limits (accepted) - A skill that upstream removes or renames keeps its last local copy; nothing prunes it. - Upstream prompts change with no diff to review (tracks `main`). - Whether `higgsfield auth token` stays local is unverified (closed-source binary), hence the 15 s bound. --- ### Task 1: Lock entry and gitignore **Files:** - Modify: `plugins.lock.json` (new `higgsfield` entry before `graphifyy`) - Modify: `.gitignore` (link side after `skills/21st-*`, source side and sync stage after `skills-external/21st-*/`) **Interfaces:** - Consumes: nothing. - Produces: lock key `higgsfield` with `version` (read by Tasks 4 and 5); ignore rules `skills/higgsfield-*`, `skills-external/higgsfield-*/` and `skills-external/.higgsfield-stage.*/` (LRN-025: both states of a toggleable artifact). - [ ] **Step 1: Apply the lock patch** Run: `git apply docs/superpowers/plans/2026-09-30-higgsfield-pack.patches/01-lock.patch` ````diff --- a/plugins.lock.json +++ b/plugins.lock.json @@ -25,6 +25,11 @@ "version": "latest", "note": "21st.dev CLI (bin `21st`) — standalone CLI + a pack of 7 skills, no MCP, no API key: auth is `21st login` (browser token in ~/.config/21st). Install: npm install -g @21st-dev/cli. The skill pack is staged-installed into skills-external/21st-* by install-plugins.sh Step 8.7 — `21st skills install` refuses to write through the ~/.claude/skills symlink." }, + "higgsfield": { + "source": "npm:@higgsfield/cli", + "version": "latest", + "note": "Higgsfield CLI (bins `higgsfield`, `higgs`) — image, video, audio and brand media generation, metered credits; auth is `higgsfield auth login` (browser). Install: npm install -g @higgsfield/cli. The package vendors its binary in a postinstall script; if npm holds it back, add --allow-scripts=@higgsfield/cli. The upstream skills are git-cloned from https://github.com/higgsfield-ai/skills (tracks main, no pin) into skills-external/higgsfield-* by lib/higgsfield-skills.sh (install-plugins.sh Step 8.6, refreshed by update-all.sh); a skill upstream removes keeps its last local copy. OFF by default and in no profile: `lib/toggle-external.sh enable higgsfield` links the 7 allowlisted media skills (HIGGSFIELD_MEDIA_SKILLS), `enable higgsfield-websites` the landing-page aid." + }, "graphifyy": { "source": "pypi:graphifyy", "version": "latest", ```` - [ ] **Step 2: Apply the gitignore patch** Run: `git apply docs/superpowers/plans/2026-09-30-higgsfield-pack.patches/01-gitignore.patch` ````diff --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,11 @@ # membership, so the pack can gain a skill with no edit here. skills/21st-* +# Higgsfield skill pack symlinks — created on demand by toggle-external.sh +# (`enable higgsfield` / `enable higgsfield-websites`). The pack is OFF by +# default and in no profile, so these usually don't exist. +skills/higgsfield-* + # Context7 docs-lookup skill — installed by `ctx7 setup --claude --cli` # (install-plugins.sh Step 6, when absent) into ~/.claude/skills (a symlink to # this repo's skills/). ctx7-managed and re-created on demand — not vendored here. @@ -236,6 +241,13 @@ # layout and the content is sha256-verified against 21st.dev's manifest. skills-external/21st-*/ +# Higgsfield skill pack — machine-owned: a git clone of higgsfield-ai/skills, +# staged by lib/higgsfield-skills.sh (install-plugins.sh Step 8.6) and moved +# here, refreshed by update-all.sh. Not vendored: it tracks upstream main. +# The second line is the helper's stage, left behind only by a killed run. +skills-external/higgsfield-*/ +skills-external/.higgsfield-stage.*/ + # npx `skills add` project-scope artifacts — darwin-skill copies itself into # the repo's .agents/ and writes skills-lock.json at root. Our own agents live # in agents/ (no dot) and stay tracked. Anchored to root so only the dotted ```` - [ ] **Step 3: Verify** Run: ```bash python3 -c "import json;d=json.load(open('plugins.lock.json'))['higgsfield'];assert d['version']=='latest' and 'managed_by' not in d;print('LOCK_OK')" git check-ignore -q skills/higgsfield-generate && git check-ignore -q skills-external/higgsfield-generate/SKILL.md && git check-ignore -q skills-external/.higgsfield-stage.abc123/src/x && echo IGNORED_ALL git check-ignore -q --no-index skills/feat/SKILL.md || echo CONTROL_OK ``` Expected: `LOCK_OK`, `IGNORED_ALL`, `CONTROL_OK` (`--no-index` makes git test the rules against a tracked path too, so an overbroad rule would fail here). - [ ] **Step 4: Commit** ```bash git add plugins.lock.json .gitignore git commit -m "chore(higgsfield): lock entry and gitignore for the skill pack" ``` --- ### Task 2: Sync helper, CLI probes and their suite **Files:** - Create: `lib/tests/higgsfield.test.sh` (from `docs/superpowers/plans/2026-09-30-higgsfield-pack.patches/02-higgsfield.test.sh`) - Create: `lib/higgsfield-skills.sh` (from `docs/superpowers/plans/2026-09-30-higgsfield-pack.patches/02-higgsfield-skills.sh`) **Interfaces:** - Consumes: nothing. - Produces: - `HIGGSFIELD_SKILLS_URL` (env value wins over the upstream default). - `higgsfield_sync_skills `: prints the number of skills synced on stdout; returns 0 when at least one skill was synced, 1 otherwise (existing copies untouched). Stages inside `/skills-external/.higgsfield-stage.*` so each replacement is a rename on one filesystem. - `higgsfield_cli_ok`: returns 0 when `higgsfield version` answers; prints nothing. - `higgsfield_signed_in`: returns 0 when `higgsfield auth token` succeeds; prints nothing. - Internal: `_higgsfield_adopt `, `_higgsfield_probe `. The clone disables every credential prompt (terminal, askpass program, credential helper): a private or deleted upstream fails at once. - Suite helpers later tasks reuse: `expect`, `expect_has`, `expect_not`, `verdict`, `yn`, `entries`, `git_q`, `$WORK`, `$ROOT`, `$BIN` (fake `higgsfield` and `21st`), `$CLEAN` (a PATH with the core tools and no CLI); the file ends with a `# ── tally ──` block that must stay last. - [ ] **Step 1: Write the failing suite** Run: `cp docs/superpowers/plans/2026-09-30-higgsfield-pack.patches/02-higgsfield.test.sh lib/tests/higgsfield.test.sh` ````bash #!/usr/bin/env bash # lib/tests/higgsfield.test.sh — hermetic suite for the Higgsfield pack. # sync lib/higgsfield-skills.sh against a local git repo shaped like # upstream (no network), and its CLI probes against a fake CLI # toggle lib/toggle-external.sh `higgsfield` / `higgsfield-websites` # against a fixture tree, fake CLIs first on PATH # wiring static locks on the installers (order, off by default) # Each named case prints one `PASS ` or `FAIL :
` line. set -u ROOT="$(cd "$(dirname "$0")/../.." && pwd)" pass=0; fail=0; errs="" # expect