@slamb2k/mad-skills 2.0.56 → 2.0.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mad-skills",
3
3
  "description": "AI-assisted planning, development and governance tools",
4
- "version": "2.0.56",
4
+ "version": "2.0.57",
5
5
  "author": {
6
6
  "name": "slamb2k",
7
7
  "url": "https://github.com/slamb2k"
package/hooks/hooks.json CHANGED
@@ -2,7 +2,10 @@
2
2
  "hooks": {
3
3
  "SessionStart": [{
4
4
  "matcher": "startup|clear|compact",
5
- "hooks": [{ "type": "command", "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/slamb2k\"; node \"$_R/hooks/session-guard.cjs\" check", "timeout": 30 }]
5
+ "hooks": [
6
+ { "type": "command", "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/slamb2k\"; node \"$_R/hooks/session-guard.cjs\" check", "timeout": 30 },
7
+ { "type": "command", "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/slamb2k\"; bash \"$_R/skills/handover/scripts/handover.sh\" load", "timeout": 10 }
8
+ ]
6
9
  }],
7
10
  "UserPromptSubmit": [{
8
11
  "hooks": [{ "type": "command", "command": "_R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/slamb2k\"; node \"$_R/hooks/session-guard.cjs\" remind", "timeout": 10 }]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slamb2k/mad-skills",
3
- "version": "2.0.56",
3
+ "version": "2.0.57",
4
4
  "description": "Claude Code skills collection — full lifecycle development tools",
5
5
  "type": "module",
6
6
  "repository": {
@@ -76,6 +76,8 @@ Parse optional flags from the request:
76
76
  - `--no-ship`: Stop after Stage 8 docs update
77
77
  - `--parallel-impl`: Split implementation into parallel agents when independent
78
78
  - `--no-superpowers`: Force the standalone pipeline even when Superpowers is installed
79
+ - `--handoff`: Skip the execution-mode question and hand off to a clean session
80
+ - `--no-handoff`: Skip the execution-mode question and run here now
79
81
 
80
82
  ---
81
83
 
@@ -91,6 +93,7 @@ Before starting, check all dependencies in this table:
91
93
  | feature-dev:code-architect | agent | — | no | fallback | Uses general-purpose agent |
92
94
  | feature-dev:code-reviewer | agent | — | no | fallback | Uses general-purpose agent |
93
95
  | superpowers | plugin | on-disk glob via scripts/lib/superpowers.js | no | fallback | Routes Stage 4 impl core to superpowers:executing-plans / subagent-driven-development when present; see references/superpowers-deferral.md |
96
+ | handover | skill | `ls .claude/skills/handover/SKILL.md ~/.claude/skills/handover/SKILL.md ~/.claude/plugins/marketplaces/slamb2k/skills/handover/SKILL.md 2>/dev/null` | no | fallback | Powers the "hand off to a clean session" execution mode; ships with mad-skills, so normally present |
94
97
 
95
98
  For each row, in order:
96
99
  1. Run the Check command (for cli/npm) or test file existence (for agent/skill)
@@ -193,6 +196,67 @@ Before starting Stage 1, verify the working tree is suitable for building:
193
196
 
194
197
  ---
195
198
 
199
+ ## Execution Mode
200
+
201
+ `/build` runs every heavy stage in subagents, so the primary conversation stays
202
+ compact *during* the build. The one thing subagents can't fix is a context
203
+ window that's **already** large when you invoke `/build` — the orchestrator
204
+ (this thread) still reads reports and runs the review/ship loop on top of
205
+ whatever came before. For that, a clean start beats a clean middle.
206
+
207
+ So there is exactly one execution-mode decision, and subagents are always on
208
+ underneath either choice:
209
+
210
+ - **Run here now** — orchestrate the build in this session, stages in subagents.
211
+ - **Hand off to a clean session** — write a handover, arm the resume signal, and
212
+ let a fresh session run the *same* `/build` with its own subagents.
213
+
214
+ These are mutually exclusive — one stops here, one continues here. Do **not**
215
+ offer a "clear? yes/no" toggle on top of run-now; the handover mode *replaces*
216
+ the run-now decision.
217
+
218
+ **Resolve the mode:**
219
+
220
+ 1. If `--no-handoff` → run here now. Skip to Stage 1.
221
+ 2. If `--handoff` → hand off (only if the handover skill exists; else warn it's
222
+ unavailable and run here now).
223
+ 3. If the handover skill is **not** installed (pre-flight) → run here now
224
+ silently. No question.
225
+ 4. Otherwise, decide whether to *offer* the hand-off at all. Only offer it when a
226
+ clean start would actually help **and** the plan can survive the reset:
227
+ - **Context already large** — this session has had substantial prior work
228
+ before `/build` (long conversation, many file reads, a prior task), so the
229
+ orchestrator would start bloated. A fresh `/build` invocation in an empty
230
+ session does not need this — just run here now.
231
+ - **Plan is self-contained** — PLAN is a spec file or a complete written plan
232
+ that a handover doc can capture losslessly. If the plan leans on nuance from
233
+ *this* conversation (decisions made live, things looked at together), a
234
+ handover is lossy — prefer run-here-now so that context isn't thrown away.
235
+
236
+ If **both** hold, ask via `AskUserQuestion`:
237
+ ```
238
+ "This session already carries significant context. Hand this build off to a
239
+ clean session, or run it here now?"
240
+ ```
241
+ Options:
242
+ - **"Run here now (Recommended)"** — orchestrate in this session (subagents underneath).
243
+ - **"Hand off to a clean session"** — reset context, resume the build fresh.
244
+
245
+ If either condition fails, don't ask — run here now.
246
+
247
+ **If handing off:** capture the resolved PLAN and any Stage-2 clarifications
248
+ gathered so far, then invoke the `handover` skill. The handover document's
249
+ "next steps" MUST be a single resume action: re-run this exact build in the
250
+ fresh session, e.g. `/build {original PLAN argument}` (plus any active flags,
251
+ minus `--handoff`). Include the resolved plan content and PROJECT_CONFIG so the
252
+ fresh session doesn't re-derive them. The handover skill arms the one-shot
253
+ signal and tells the user to `/clear`. **Stop here** — do not run Stage 1; the
254
+ fresh session does.
255
+
256
+ **If running here now:** continue to Stage 1 unchanged.
257
+
258
+ ---
259
+
196
260
  ## Stage 1: Explore
197
261
 
198
262
  Launch **feature-dev:code-explorer** (fallback: general-purpose):
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: handover
3
+ description: Persist a session handover document and signal the next fresh session to resume from it. Use when the user types /handover, says they want to hand off, checkpoint, wrap up, clear context, or start fresh while preserving state, or asks to carry work into a new session with clean optimised context. Captures everything a brand-new session needs — task, status, next steps, key files, decisions, gotchas, git state — writes it to disk, arms a one-shot signal, and tells the user to /clear so the next session auto-loads it.
4
+ argument-hint: repo, tmp, commit (optional target; default repo)
5
+ allowed-tools: Bash, Read, Write
6
+ ---
7
+
8
+ # Handover - Clean-Context Session Handoff
9
+
10
+ When this skill is invoked, IMMEDIATELY output the banner below before doing anything else.
11
+ Pick ONE tagline at random — vary your choice each time.
12
+ CRITICAL: Reproduce the banner EXACTLY character-for-character, preserving all leading spaces.
13
+
14
+ ```
15
+ {tagline}
16
+
17
+ ██╗ ██╗ █████╗ ███╗ ██╗██████╗ ██████╗ ██╗ ██╗███████╗██████╗
18
+ ██║ ██║██╔══██╗████╗ ██║██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
19
+ ███████║███████║██╔██╗ ██║██║ ██║██║ ██║██║ ██║█████╗ ██████╔╝
20
+ ██╔══██║██╔══██║██║╚██╗██║██║ ██║██║ ██║╚██╗ ██╔╝██╔══╝ ██╔══██╗
21
+ ██║ ██║██║ ██║██║ ╚████║██████╔╝╚██████╔╝ ╚████╔╝ ███████╗██║ ██║
22
+ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚═════╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝
23
+ ```
24
+
25
+ Taglines:
26
+ - 🪂 Packing the parachute for a clean landing...
27
+ - 🧳 Bagging up the context, checking out...
28
+ - 🤝 Passing the baton to a fresh runner!
29
+ - 📦 Boxing up everything the next session needs!
30
+ - 🧹 Clearing the desk, leaving a tidy note!
31
+ - 🛟 Nobody loses the thread on my watch!
32
+ - 🌅 Fresh session, same mission!
33
+
34
+ ---
35
+
36
+ ## What this does
37
+
38
+ Capture the live state of this session into a handover document, arm a one-shot
39
+ signal, and hand the user off to a clean session that will automatically resume
40
+ from the document. The point is to **reset the context window without losing the
41
+ thread** — the next session starts lean but fully briefed.
42
+
43
+ Long sessions accumulate noise: dead ends, superseded plans, stale file reads. A
44
+ fresh session is faster and sharper, but naively starting over loses hard-won
45
+ context. `/handover` distills only what the *next* session needs, persists it, and
46
+ signals that session to pick it up — once. It will not re-read old handovers on
47
+ unrelated future sessions, because the signal is consumed on first read.
48
+
49
+ ## Usage
50
+
51
+ ```
52
+ /handover # default: HANDOVER.md in repo root, kept OUT of git
53
+ /handover repo # same as default (explicit)
54
+ /handover tmp # write under /tmp — never touches the repo at all
55
+ /handover commit # write docs/handovers/HANDOVER-<timestamp>.md, meant to be committed
56
+ ```
57
+
58
+ Read the argument from what the user typed. If none given, use `repo`.
59
+
60
+ ## Pre-flight
61
+
62
+ Before starting, check dependencies:
63
+
64
+ | Dependency | Type | Check | Required | Resolution | Detail |
65
+ |-----------|------|-------|----------|------------|--------|
66
+ | git | cli | `git rev-parse --show-toplevel` | no | fallback | Not in a git repo → use cwd for `repo` mode; skip `.git/info/exclude` step |
67
+ | jq | cli | `command -v jq` | no | fallback | Signal loader falls back to sed + raw-stdout injection; no behavior change |
68
+
69
+ Resolve the plugin root once for the signal command:
70
+
71
+ ```bash
72
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/marketplaces/slamb2k}"
73
+ ```
74
+
75
+ ## What to do
76
+
77
+ Work through these steps in order. Don't skip the verification at the end.
78
+
79
+ ### 1. Resolve the target path
80
+
81
+ First get the repo root and a timestamp:
82
+
83
+ ```bash
84
+ git rev-parse --show-toplevel 2>/dev/null # repo root, or empty if not a git repo
85
+ date +%Y-%m-%d-%H%M
86
+ ```
87
+
88
+ Then pick the path based on the argument:
89
+
90
+ - **`repo`** (default): `<repo_root>/HANDOVER.md`. If not inside a git repo, use the
91
+ current working directory instead. After writing, keep it out of version control
92
+ by appending `HANDOVER.md` to `<repo_root>/.git/info/exclude` if it's a git repo
93
+ and not already listed there. This is a *local* ignore — it never modifies the
94
+ tracked `.gitignore`, so it won't show up in anyone else's checkout or your diffs.
95
+ - **`tmp`**: `/tmp/claude-handover/<key>/HANDOVER.md` where `<key>` is
96
+ `printf '%s' "$(pwd)" | cksum | cut -d' ' -f1`. Create the directory first.
97
+ Nothing is written inside the repo.
98
+ - **`commit`**: `<repo_root>/docs/handovers/HANDOVER-<timestamp>.md`. Create the
99
+ `docs/handovers/` directory if needed. Do **not** ignore it — this variant exists
100
+ precisely so the handover lands in git history as a durable checkpoint. Mention to
101
+ the user that they'll want to commit it.
102
+
103
+ ### 2. Write the handover document
104
+
105
+ This is the core of the skill — the document quality determines whether the next
106
+ session is productive or lost. Follow the structure in
107
+ `references/handover-template.md`. Read that file now if you haven't.
108
+
109
+ Fill it from the **actual conversation and repo state**, not generic boilerplate.
110
+ Be concrete: real file paths, real function names, real commands, real decisions.
111
+ Write for a competent engineer who has *zero* memory of this session — every
112
+ assumption in your head right now is invisible to them unless you write it down.
113
+
114
+ Gather git state to embed in the document:
115
+
116
+ ```bash
117
+ git -C <repo_root> branch --show-current
118
+ git -C <repo_root> status --short
119
+ git -C <repo_root> log --oneline -8
120
+ ```
121
+
122
+ Optimise for *their* context budget: include what unblocks action, link to files
123
+ rather than pasting large code, and cut the narrative of how you got here unless a
124
+ dead end is a genuine landmine worth a warning.
125
+
126
+ ### 3. Arm the one-shot signal
127
+
128
+ After the document is written, run (using the `PLUGIN_ROOT` resolved in pre-flight):
129
+
130
+ ```bash
131
+ bash "$PLUGIN_ROOT/skills/handover/scripts/handover.sh" signal "<absolute_path_to_handover>"
132
+ ```
133
+
134
+ This drops a signal keyed to the current project directory. The next session's
135
+ `SessionStart` hook — shipped with this plugin in `hooks/hooks.json` — detects it,
136
+ injects the handover as context, and deletes the signal so it fires exactly once.
137
+ Use the **absolute** path.
138
+
139
+ ### 4. Hand off to a fresh session
140
+
141
+ Tell the user plainly that the handover is ready and they should start the fresh
142
+ session themselves. You **cannot** trigger `/clear` programmatically — it is a
143
+ user-only command — so the final step is theirs. Say something like:
144
+
145
+ > Handover written to `<path>` and the next session is armed. Type **`/clear`**
146
+ > (or **`/new`**) now — the fresh session will automatically load this handover and
147
+ > pick up where we left off. Nothing else gets auto-loaded; the signal is consumed
148
+ > on first read.
149
+
150
+ Keep this final message short. The work is done; don't bury the one action they
151
+ need to take.
152
+
153
+ ## Important constraints
154
+
155
+ - **`/clear` is the user's to type.** No skill, hook, or command can clear the
156
+ context window automatically. Always end by asking them to do it.
157
+ - **The signal is one-shot and project-scoped.** It's keyed to the working
158
+ directory and deleted on first read, so handovers never leak into unrelated
159
+ sessions. A `HANDOVER.md` left sitting in a repo is inert unless re-armed.
160
+ - **Don't pollute git by default.** Only the `commit` variant is meant to be
161
+ tracked. `repo` mode relies on `.git/info/exclude`; `tmp` mode stays entirely
162
+ outside the repo.
163
+ - **If `/handover` is run again later**, overwrite the existing document and
164
+ re-arm the signal — the latest state wins.
@@ -0,0 +1,89 @@
1
+ # Handover document template
2
+
3
+ Fill every section that applies. Drop sections that genuinely don't (e.g. no open
4
+ questions). Lead with what unblocks action; a fresh session should be able to make
5
+ its **next move within the first minute** of reading this.
6
+
7
+ Write concretely. "Fix the bug in the parser" is useless; "`parseImportFile()` in
8
+ `src/import.js:42` throws on empty `days` — needs a guard before the `Object.entries`
9
+ loop" is a handover. Prefer absolute or repo-relative file paths with line numbers.
10
+
11
+ ---
12
+
13
+ ```markdown
14
+ # Handover — <short task title>
15
+
16
+ **Date:** <YYYY-MM-DD HH:MM> · **Branch:** <git branch> · **Repo:** <path>
17
+
18
+ ## TL;DR
19
+ One or two sentences: what we're doing and what the very next action is.
20
+
21
+ ## Goal / definition of done
22
+ The north star. What does "finished" look like? Include acceptance criteria or
23
+ the user's original ask in their words if it matters.
24
+
25
+ ## Current status
26
+ What's done and working (verified vs assumed — say which). What's the state of the
27
+ tree right now. If something is half-built, say exactly how far it got.
28
+
29
+ ## Next steps
30
+ Ordered, concrete, actionable. The first item should be immediately doable.
31
+ 1. ...
32
+ 2. ...
33
+
34
+ ## Key files & entry points
35
+ The map. Where the relevant code lives and what each piece does.
36
+ - `path/to/file.ext:line` — what it is / why it matters
37
+ - ...
38
+
39
+ ## Key decisions & rationale
40
+ Choices already made that the next session must respect, and *why* — so it doesn't
41
+ unknowingly relitigate or contradict them.
42
+ - Decided X because Y. Alternative Z was rejected because ...
43
+
44
+ ## Gotchas, dead ends & landmines
45
+ Things that wasted time or will bite again. Approaches already tried that DON'T
46
+ work (so the next session doesn't repeat them). Environment quirks, flaky steps,
47
+ ordering constraints.
48
+ - Tried A → failed because B. Don't retry without addressing B.
49
+ - Watch out for ...
50
+
51
+ ## How to build / test / run
52
+ Exact commands. The next session shouldn't have to rediscover these.
53
+ - Build: `...`
54
+ - Test: `...`
55
+ - Run / verify: `...`
56
+
57
+ ## Open questions & assumptions
58
+ Unresolved decisions awaiting the user, and assumptions made that might be wrong.
59
+ Flag anything the user still needs to answer.
60
+ - [ ] Question: ... (suggested default: ...)
61
+ - Assumption: ... (if wrong, then ...)
62
+
63
+ ## Git state
64
+ - Branch: <branch> (tracking <remote/branch> or "local-only")
65
+ - Uncommitted changes: <summary of `git status --short`, or "clean">
66
+ - Recent commits:
67
+ ```
68
+ <git log --oneline -8>
69
+ ```
70
+
71
+ ## Context the next session can't infer
72
+ Anything important that isn't in the code, git history, or CLAUDE.md — the stuff
73
+ living only in this conversation. External constraints, user preferences expressed
74
+ mid-session, credentials/access notes (reference, don't paste secrets), URLs,
75
+ ticket numbers, people involved.
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Filling guidance
81
+
82
+ - **Verified vs assumed:** if you ran the test and it passed, say "verified". If you
83
+ think it works but didn't check, say "assumed — not yet run". A fresh session has
84
+ no way to tell otherwise and false confidence is expensive.
85
+ - **Link, don't paste:** point to files and line ranges rather than dumping large
86
+ code blocks. The next session can read them on demand; bloating the handover just
87
+ refills the context window you're trying to clear.
88
+ - **Keep it skimmable:** headers, short bullets, code spans for paths/commands. A
89
+ wall of prose defeats the purpose.
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+ # handover.sh — companion to the `handover` skill.
3
+ #
4
+ # handover.sh signal <abs_handover_path> [cwd]
5
+ # Drop a one-shot signal keyed to the current project (cwd) pointing at
6
+ # the handover document. The next session's SessionStart hook consumes it.
7
+ #
8
+ # handover.sh load
9
+ # SessionStart hook entrypoint. Reads the event JSON on stdin; if a signal
10
+ # exists for this cwd, emits the handover as additionalContext and deletes
11
+ # the signal (one-shot — a stale HANDOVER.md is never re-injected).
12
+ #
13
+ # The signal is keyed on the working directory, NOT the session id, because the
14
+ # session id changes after /clear. cwd is stable across a clear, so the fresh
15
+ # session finds the signal its predecessor left.
16
+ set -euo pipefail
17
+
18
+ SIGNAL_DIR="/tmp/claude-handover"
19
+
20
+ _key() {
21
+ # Stable, dependency-free hash of a directory path. cksum is POSIX.
22
+ printf '%s' "$1" | cksum | cut -d' ' -f1
23
+ }
24
+
25
+ cmd="${1:-load}"
26
+
27
+ case "$cmd" in
28
+ signal)
29
+ handover_path="${2:?usage: handover.sh signal <abs_handover_path> [cwd]}"
30
+ cwd="${3:-$(pwd)}"
31
+ mkdir -p "$SIGNAL_DIR"
32
+ key="$(_key "$cwd")"
33
+ printf '%s\n' "$handover_path" > "$SIGNAL_DIR/$key.signal"
34
+ printf 'handover: signal armed for %s -> %s\n' "$cwd" "$handover_path"
35
+ ;;
36
+
37
+ load)
38
+ input="$(cat)"
39
+
40
+ if command -v jq >/dev/null 2>&1; then
41
+ cwd="$(printf '%s' "$input" | jq -r '.cwd // empty')"
42
+ else
43
+ cwd="$(printf '%s' "$input" | sed -n 's/.*"cwd"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)"
44
+ fi
45
+ [ -n "$cwd" ] || cwd="$(pwd)"
46
+
47
+ key="$(_key "$cwd")"
48
+ signal="$SIGNAL_DIR/$key.signal"
49
+ [ -f "$signal" ] || exit 0 # no handover pending — silent no-op
50
+
51
+ handover_path="$(head -n1 "$signal")"
52
+ rm -f "$signal" # one-shot: consume the signal
53
+ [ -f "$handover_path" ] || exit 0 # document vanished — nothing to inject
54
+
55
+ content="$(cat "$handover_path")"
56
+ preamble="The previous session left a handover document at ${handover_path} and signalled that this session should resume from it. Treat it as your primary context for continuing the work. Read any files it references before acting. This is one-shot: do not seek out or re-read handover documents in future sessions unless signalled again."
57
+
58
+ if command -v jq >/dev/null 2>&1; then
59
+ jq -n --arg pre "$preamble" --arg body "$content" \
60
+ '{hookSpecificOutput:{hookEventName:"SessionStart", additionalContext:($pre + "\n\n---\n\n" + $body)}}'
61
+ else
62
+ # Fallback: SessionStart adds raw stdout to context too.
63
+ printf '%s\n\n---\n\n%s\n' "$preamble" "$content"
64
+ fi
65
+ ;;
66
+
67
+ *)
68
+ printf 'handover.sh: unknown command "%s" (expected: signal | load)\n' "$cmd" >&2
69
+ exit 1
70
+ ;;
71
+ esac
@@ -0,0 +1,35 @@
1
+ {
2
+ "skill": "handover",
3
+ "cases": [
4
+ {
5
+ "name": "explicit slash invocation",
6
+ "prompt": "/handover",
7
+ "expect_skill": "handover",
8
+ "assertions": [
9
+ "Writes a handover document to HANDOVER.md in the repo root by default",
10
+ "Arms the one-shot signal via scripts/handover.sh signal with an absolute path",
11
+ "Tells the user to type /clear to start the fresh session themselves"
12
+ ]
13
+ },
14
+ {
15
+ "name": "natural language wrap-up",
16
+ "prompt": "Let's wrap up and start fresh with a clean context window without losing where we are.",
17
+ "expect_skill": "handover",
18
+ "assertions": [
19
+ "Recognizes the intent to reset context while preserving state",
20
+ "Captures task, status, next steps, key files, decisions, and git state",
21
+ "Does not attempt to run /clear itself — leaves that to the user"
22
+ ]
23
+ },
24
+ {
25
+ "name": "committed checkpoint variant",
26
+ "prompt": "/handover commit",
27
+ "expect_skill": "handover",
28
+ "assertions": [
29
+ "Writes to docs/handovers/HANDOVER-<timestamp>.md instead of the ignored repo-root file",
30
+ "Does not add the file to .git/info/exclude",
31
+ "Notes the user will want to commit the checkpoint"
32
+ ]
33
+ }
34
+ ]
35
+ }
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: hoist
3
+ description: >-
4
+ Generate secure, low-infrastructure release pipelines that publish artifacts
5
+ directly — language packages (npm, PyPI, crates, RubyGems, NuGet, Go), GitHub
6
+ Releases with binaries, static sites/Pages, or serverless functions — without
7
+ building a container image. OIDC/trusted publishing, provenance, idempotent
8
+ publish guards, and three trigger models (auto-bump with optional approval,
9
+ tag, manual). The non-container sibling of /dock. Use when releasing a package
10
+ or app that doesn't ship as a container.
11
+ argument-hint: "--skip-interview, --dry-run, --registry <name>"
12
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion, Agent
13
+ ---
14
+
15
+ # Hoist - Non-Container Release Pipelines
16
+
17
+ When this skill is invoked, IMMEDIATELY output the banner below before doing anything else.
18
+ Pick ONE tagline at random — vary your choice each time.
19
+ CRITICAL: Reproduce the banner EXACTLY character-for-character. The first line of the art has 4 leading characters (one invisible braille-blank + 3 spaces) — you MUST preserve them.
20
+
21
+ ```
22
+ {tagline}
23
+
24
+ ⠀ ██╗██╗ ██╗ ██████╗ ██╗███████╗████████╗
25
+ ██╔╝██║ ██║██╔═══██╗██║██╔════╝╚══██╔══╝
26
+ ██╔╝ ███████║██║ ██║██║███████╗ ██║
27
+ ██╔╝ ██╔══██║██║ ██║██║╚════██║ ██║
28
+ ██╔╝ ██║ ██║╚██████╔╝██║███████║ ██║
29
+ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝
30
+ ```
31
+
32
+ Taglines:
33
+ - 📦 Up and away — published!
34
+ - 🏗️ Hoisting your release skyward!
35
+ - 🚀 From main to registry in one pull!
36
+ - 🪝 Latched on, lifting off!
37
+ - ⬆️ Straight to the top shelf!
38
+ - 🎁 Wrapped, signed, and shipped!
39
+ - 🛎️ Release, served fresh!
40
+ - 🔖 Tag it and bag it!
41
+
42
+ ## Flags
43
+ - `--skip-interview`: detected + platform-aware defaults
44
+ - `--dry-run`: show generated files without writing
45
+ - `--registry <name>`: force the target registry
46
+
47
+ ## Output Formatting
48
+ (Input box, Pre-flight table, stage headers, status icons — copy the conventions
49
+ from skills/dock/SKILL.md.)
50
+
51
+ ## Pre-flight
52
+ 6-column dependency table: git (required, stop), gh (optional for GitHub release
53
+ ops), sync (optional skill, fallback git pull), node/language toolchain (optional,
54
+ detected). Follow the resolution-strategy list format used by other skills.
55
+
56
+ ## Platform Detection
57
+ Detect github vs azdo from the remote URL (same block as skills/dock/SKILL.md).
58
+
59
+ ## Phase 0: Sync
60
+ Invoke /sync (fallback git pull).
61
+
62
+ ## Phase 1: Detection
63
+ Explore subagent using references/interview-guide.md#detection-prompt → DETECTION_REPORT.
64
+
65
+ ## Phase 2: Interview
66
+ Follow references/interview-guide.md#interview-questions. Compile HOIST_CONFIG
67
+ (target, registry/host, trigger model, approval gate, signing).
68
+
69
+ ## Phase 3: Generate
70
+ Read references/release-templates.md and references/hardening.md. Emit the CI
71
+ workflow for the detected target + chosen trigger (secure by default: id-token,
72
+ provenance, idempotent publish guard, concurrency; token exceptions per
73
+ hardening.md). For binaries, add SHA256SUMS + optional signing. Generate
74
+ deploy/SETUP.md from references/setup-guides.md.
75
+
76
+ ## Phase 4: Verify
77
+ Validate workflow YAML. Confirm the generated workflow carries the required
78
+ hardening for its target (OIDC/`id-token: write` or a flagged token secret;
79
+ provenance where supported; the version-exists guard; publish-before-tag).
80
+ --dry-run previews without writing.
81
+
82
+ ## Final Report
83
+ Box report with target, trigger model, generated files, and a 🔐 Required setup
84
+ section pointing at deploy/SETUP.md.
85
+
86
+ ## Integration
87
+ Complements /dock (containers) — pick whichever fits. Runs after /rig; /ship's
88
+ merge can trigger the generated auto-bump release. Only the serverless target may
89
+ reference /keel for cloud identity.
@@ -0,0 +1,62 @@
1
+ # Release Hardening Reference
2
+
3
+ How `/hoist` hardens the release pipelines it generates. Same ethos as `/dock`,
4
+ translated from container promotion to artifact publishing. Secure by default.
5
+
6
+ ## Trusted Publishing (OIDC)
7
+
8
+ Publish with the CI provider's OIDC identity instead of a stored token, wherever
9
+ the registry supports it:
10
+
11
+ - **npm** — `permissions: id-token: write` + `npm publish --provenance`. Configure
12
+ the package's trusted publisher on npmjs.com (repo + workflow). No `NODE_AUTH_TOKEN`.
13
+ - **PyPI** — `pypa/gh-action-pypi-publish` with `id-token: write`; configure a
14
+ PyPI trusted publisher. No API token.
15
+ - **RubyGems** — trusted publishing via OIDC; configure on rubygems.org.
16
+ - **GitHub Pages** — `id-token: write` + `actions/deploy-pages`.
17
+ - **AWS Lambda** — `aws-actions/configure-aws-credentials` with `role-to-assume`
18
+ (GitHub OIDC → IAM role). No access keys.
19
+
20
+ Azure Pipelines uses a **Workload Identity Federation service connection**
21
+ (`azureSubscription`) where cloud auth is needed.
22
+
23
+ ## Provenance & Attestation
24
+
25
+ - npm: `--provenance` (SLSA provenance attestation).
26
+ - PyPI: `gh-action-pypi-publish` emits attestations by default.
27
+ - Binaries: generate SLSA build provenance and attach it to the release.
28
+
29
+ ## Idempotent Publish Guard
30
+
31
+ Publish is **check-then-act** and runs **before** any git tag/commit, so a failed
32
+ publish leaves git clean and a re-run is safe (recovery mode):
33
+
34
+ - npm: `npm view <pkg>@<version> version` — skip publish if it returns.
35
+ - PyPI: query the simple index / `pip index versions`.
36
+ - crates.io: query the index; RubyGems: `gem list -r -e`.
37
+ - GitHub Release: `gh release view vX.Y.Z` — skip if it exists.
38
+
39
+ Only after a successful (or already-present) publish does the workflow tag +
40
+ create the release. A `concurrency:` group keyed on workflow + ref with
41
+ `cancel-in-progress` prevents overlapping release runs.
42
+
43
+ ## Approval Gate
44
+
45
+ For the auto-bump-on-merge trigger, optionally run the publish job in a protected
46
+ **environment** so it pauses for human approval before publishing:
47
+
48
+ - GitHub: `environment: release` on the publish job + required reviewers configured
49
+ on the `release` environment.
50
+ - Azure: an environment with a manual-approval check.
51
+
52
+ ## Token Exceptions
53
+
54
+ Registries/platforms without OIDC trusted publishing at authoring time use a
55
+ **scoped token stored as a CI secret** — the documented exception to the
56
+ no-token rule. Flag these in `deploy/SETUP.md`:
57
+
58
+ - crates.io (`CARGO_REGISTRY_TOKEN`), NuGet (`NUGET_API_KEY`),
59
+ Cloudflare (`CLOUDFLARE_API_TOKEN`), Vercel (`VERCEL_TOKEN`),
60
+ Deno Deploy (`DENO_DEPLOY_TOKEN`).
61
+
62
+ Use the narrowest scope the platform allows (publish-only, single package/project).
@@ -0,0 +1,28 @@
1
+ # Interview Guide
2
+
3
+ ## Detection Prompt
4
+
5
+ Scan the repo and return a DETECTION_REPORT (max 20 lines):
6
+ - language/framework
7
+ - manifest(s): package.json / pyproject.toml / Cargo.toml / *.gemspec / *.csproj / go.mod
8
+ - target family: `package` (library) | `binaries` (app shipping executables) |
9
+ `static` (static-site framework) | `serverless` (function handler)
10
+ - detected registry from manifest metadata (npm/PyPI/crates/RubyGems/NuGet/Go)
11
+ - existing CI: .github/workflows/ , azure-pipelines.yml
12
+ - existing release config
13
+
14
+ ## Interview Questions
15
+
16
+ Ask only where detection is ambiguous; confirm otherwise.
17
+
18
+ 1. **Target family** — confirm `package` / `binaries` / `static` / `serverless`.
19
+ 2. **Registry / host** — the specific index (npm/PyPI/…), GitHub Releases vs
20
+ Azure artifacts, GitHub Pages vs Azure Static Web Apps, or the serverless
21
+ provider (Lambda/Cloudflare/Vercel/Deno).
22
+ 3. **Trigger model** — auto-bump-on-merge / tag-triggered / manual-dispatch.
23
+ 4. **Approval gate** — (auto-bump only) run publish in a protected `release`
24
+ environment with required reviewers? Default: no.
25
+ 5. **Signing** — (binaries) cosign keyless / minisign / none.
26
+
27
+ `--skip-interview`: use detected defaults + GitHub Releases/Pages, OIDC where
28
+ supported, auto-bump, no approval gate.
@@ -0,0 +1,136 @@
1
+ # Release Pipeline Templates
2
+
3
+ Canonical, composable hardened release workflows. The generator picks ONE
4
+ trigger block and ONE publish snippet for the detected target, and drops
5
+ unused jobs. Placeholders: `{DEFAULT_BRANCH}`, `{PKG_NAME}`, `{ARTIFACT}`.
6
+
7
+ ## GitHub Actions
8
+
9
+ ### Canonical release workflow
10
+
11
+ ```yaml
12
+ name: Release
13
+
14
+ on: {} # replaced by ONE trigger block from "### Trigger blocks" below
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ permissions:
21
+ contents: write # tag + create release
22
+ id-token: write # OIDC trusted publishing / keyless signing
23
+
24
+ jobs:
25
+ release:
26
+ runs-on: ubuntu-latest
27
+ # environment: release # uncomment for the optional approval gate (auto-bump)
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ with: { fetch-depth: 0 }
31
+
32
+ # Resolve VERSION per trigger — see "### Trigger blocks".
33
+ - name: Resolve version
34
+ id: version
35
+ run: echo "value=<resolved>" >> "$GITHUB_OUTPUT"
36
+
37
+ # Idempotency guard (publish-before-git-write). Example: npm.
38
+ - name: Skip if already published
39
+ id: guard
40
+ run: |
41
+ if npm view "{PKG_NAME}@${{ steps.version.outputs.value }}" version >/dev/null 2>&1; then
42
+ echo "exists=true" >> "$GITHUB_OUTPUT"
43
+ else
44
+ echo "exists=false" >> "$GITHUB_OUTPUT"
45
+ fi
46
+
47
+ - name: Build
48
+ if: steps.guard.outputs.exists == 'false'
49
+ run: echo "build {ARTIFACT}" # replaced by detected build step
50
+
51
+ # Publish — ONE snippet from "### Publish snippets by target".
52
+ - name: Publish
53
+ if: steps.guard.outputs.exists == 'false'
54
+ run: npm publish --provenance --access public
55
+
56
+ # Tag + release only after successful publish (auto-bump trigger).
57
+ - name: Tag and release
58
+ if: steps.guard.outputs.exists == 'false'
59
+ uses: softprops/action-gh-release@v2
60
+ with:
61
+ tag_name: v${{ steps.version.outputs.value }}
62
+ generate_release_notes: true
63
+ ```
64
+
65
+ ### Trigger blocks
66
+
67
+ Pick ONE and substitute into `on:` (and adjust the version-resolve step):
68
+
69
+ ```yaml
70
+ # auto-bump on merge to main
71
+ on:
72
+ push: { branches: [{DEFAULT_BRANCH}] }
73
+ # version-resolve: compute next semver patch (or conventional-commits) in-CI
74
+
75
+ # tag-triggered
76
+ on:
77
+ push: { tags: ["v*"] }
78
+ # version-resolve: VERSION = ${GITHUB_REF_NAME#v}
79
+
80
+ # manual dispatch
81
+ on:
82
+ workflow_dispatch:
83
+ inputs: { version: { description: "x.y.z", required: true } }
84
+ # version-resolve: VERSION = ${{ inputs.version }}
85
+ ```
86
+
87
+ ### Publish snippets by target
88
+
89
+ Replace the "Publish" step body:
90
+
91
+ - **npm:** `npm publish --provenance --access public`
92
+ - **PyPI:** `- uses: pypa/gh-action-pypi-publish@release/v1` (with `id-token: write`; attestations on by default)
93
+ - **RubyGems:** `gem push {ARTIFACT}.gem` (OIDC trusted publishing)
94
+ - **crates.io (token):** `cargo publish` with `CARGO_REGISTRY_TOKEN` secret
95
+ - **NuGet (token):** `dotnet nuget push {ARTIFACT}.nupkg -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json`
96
+ - **Go:** no publish step — the tag is the release; the module proxy fetches it
97
+ - **Binaries → GitHub Release:** cross-compile matrix → `sha256sum * > SHA256SUMS` → optional `cosign sign-blob`/`minisign` → `softprops/action-gh-release@v2` with `files: dist/*`
98
+ - **Static site → Pages:** `- uses: actions/upload-pages-artifact@v3` then `- uses: actions/deploy-pages@v4` (`id-token: write`)
99
+ - **Serverless (Lambda):** `- uses: aws-actions/configure-aws-credentials@v4` (`role-to-assume`) then `aws lambda update-function-code ...`
100
+
101
+ ## Azure Pipelines
102
+
103
+ Canonical release pipeline. Cloud auth (Lambda/SWA) uses a Workload Identity
104
+ Federation service connection (`azureSubscription`); package registries use OIDC
105
+ or a scoped token secret per target.
106
+
107
+ ```yaml
108
+ trigger: # pick ONE, mirroring the GitHub trigger blocks
109
+ branches: { include: [{DEFAULT_BRANCH}] } # auto-bump
110
+ # tags: { include: ["v*"] } # tag-triggered
111
+ # (manual: use the Pipelines UI "Run pipeline" with a version variable)
112
+
113
+ pool: { vmImage: ubuntu-latest }
114
+
115
+ stages:
116
+ - stage: Release
117
+ jobs:
118
+ - deployment: Publish
119
+ environment: release # optional approval gate (add a manual-approval check)
120
+ strategy:
121
+ runOnce:
122
+ deploy:
123
+ steps:
124
+ - script: |
125
+ VERSION="<resolved per trigger>"
126
+ if npm view "{PKG_NAME}@$VERSION" version >/dev/null 2>&1; then
127
+ echo "##vso[task.setvariable variable=exists]true"
128
+ else
129
+ echo "##vso[task.setvariable variable=exists]false"
130
+ fi
131
+ displayName: Idempotency guard
132
+ - script: npm publish --provenance --access public
133
+ condition: ne(variables.exists, 'true')
134
+ displayName: Publish (npm shown; swap per target)
135
+ # Cloud targets: wrap deploy in AzureCLI@2 with azureSubscription (WIF).
136
+ ```
@@ -0,0 +1,30 @@
1
+ # Setup Guides
2
+
3
+ `/hoist` writes `deploy/SETUP.md` into the target repo, tailored to the chosen
4
+ target. Bodies below (substitute `OWNER/REPO`, package name, workflow filename).
5
+
6
+ ## Generated deploy/SETUP.md
7
+
8
+ ### npm / PyPI / RubyGems (trusted publisher — no token)
9
+ - Configure the **trusted publisher** on the registry: reference repo `OWNER/REPO`
10
+ and the workflow filename (e.g. `.github/workflows/release.yml`).
11
+ - No token to create. The workflow's `id-token: write` does the rest.
12
+
13
+ ### crates.io / NuGet / Cloudflare / Vercel / Deno (Token exception)
14
+ - Create a scoped, publish-only token on the platform.
15
+ - Store it as the named CI secret (`CARGO_REGISTRY_TOKEN` / `NUGET_API_KEY` /
16
+ `CLOUDFLARE_API_TOKEN` / `VERCEL_TOKEN` / `DENO_DEPLOY_TOKEN`).
17
+ - This is the documented exception to the no-token rule.
18
+
19
+ ### GitHub Pages
20
+ - Repo Settings → Pages → Source: **GitHub Actions**. No token.
21
+
22
+ ### Serverless (AWS Lambda)
23
+ - Create an IAM role trusting the GitHub OIDC provider, condition
24
+ `sub = repo:OWNER/REPO:ref:refs/heads/main`; grant the lambda update
25
+ permissions; put the role ARN in `role-to-assume`. Or run `/keel` to
26
+ provision this.
27
+
28
+ ### Approval gate (optional, auto-bump)
29
+ - Create a `release` environment and add required reviewers so publishing pauses
30
+ for approval.
@@ -0,0 +1,36 @@
1
+ [
2
+ {
3
+ "name": "banner-display",
4
+ "prompt": "/hoist",
5
+ "assertions": [
6
+ { "type": "contains", "value": "██" },
7
+ { "type": "semantic", "value": "Displays an ASCII art banner for the hoist skill before doing anything else" }
8
+ ]
9
+ },
10
+ {
11
+ "name": "npm-trusted-publishing",
12
+ "prompt": "/hoist --skip-interview for an npm library",
13
+ "assertions": [
14
+ { "type": "semantic", "value": "Uses npm OIDC trusted publishing with no stored NODE_AUTH_TOKEN" },
15
+ { "type": "semantic", "value": "Publishes with provenance (npm publish --provenance)" },
16
+ { "type": "semantic", "value": "Guards publish with a version-already-exists check so re-runs are idempotent" }
17
+ ]
18
+ },
19
+ {
20
+ "name": "binaries-release",
21
+ "prompt": "/hoist for a Go CLI that ships cross-platform binaries",
22
+ "assertions": [
23
+ { "type": "semantic", "value": "Builds cross-platform binaries in a matrix and produces SHA256SUMS checksums" },
24
+ { "type": "semantic", "value": "Attaches the artifacts to a GitHub Release" }
25
+ ]
26
+ },
27
+ {
28
+ "name": "auto-bump-approval",
29
+ "prompt": "/hoist an npm package, auto-bump on merge to main with an approval gate before publishing",
30
+ "assertions": [
31
+ { "type": "semantic", "value": "Auto-computes the next version and publishes on merge to the default branch" },
32
+ { "type": "semantic", "value": "Runs the publish step behind an environment approval gate requiring a human reviewer" },
33
+ { "type": "semantic", "value": "Generates a deploy/SETUP.md describing the required one-time setup" }
34
+ ]
35
+ }
36
+ ]
@@ -1,6 +1,6 @@
1
1
  {
2
- "generated": "2026-07-06T03:27:34.322Z",
3
- "count": 11,
2
+ "generated": "2026-07-07T07:32:19.484Z",
3
+ "count": 13,
4
4
  "skills": [
5
5
  {
6
6
  "name": "brace",
@@ -16,7 +16,7 @@
16
16
  "name": "build",
17
17
  "directory": "build",
18
18
  "description": "Context-isolated feature development pipeline. Takes a detailed design/plan as argument and executes the full feature-dev lifecycle (explore, question, architect, implement, review, ship) inside subagents so the primary conversation stays compact. Use when you have a well-defined plan and want autonomous execution with minimal context window consumption.",
19
- "lines": 468,
19
+ "lines": 532,
20
20
  "hasScripts": false,
21
21
  "hasReferences": true,
22
22
  "hasAssets": false,
@@ -42,6 +42,26 @@
42
42
  "hasAssets": false,
43
43
  "hasTests": true
44
44
  },
45
+ {
46
+ "name": "handover",
47
+ "directory": "handover",
48
+ "description": "Persist a session handover document and signal the next fresh session to resume from it. Use when the user types /handover, says they want to hand off, checkpoint, wrap up, clear context, or start fresh while preserving state, or asks to carry work into a new session with clean optimised context. Captures everything a brand-new session needs — task, status, next steps, key files, decisions, gotchas, git state — writes it to disk, arms a one-shot signal, and tells the user to /clear so the next session auto-loads it.",
49
+ "lines": 165,
50
+ "hasScripts": true,
51
+ "hasReferences": true,
52
+ "hasAssets": false,
53
+ "hasTests": true
54
+ },
55
+ {
56
+ "name": "hoist",
57
+ "directory": "hoist",
58
+ "description": ">- Generate secure, low-infrastructure release pipelines that publish artifacts directly — language packages (npm, PyPI, crates, RubyGems, NuGet, Go), GitHub Releases with binaries, static sites/Pages, or serverless functions — without building a container image. OIDC/trusted publishing, provenance, idempotent publish guards, and three trigger models (auto-bump with optional approval, tag, manual). The non-container sibling of /dock. Use when releasing a package or app that doesn't ship as a container.",
59
+ "lines": 90,
60
+ "hasScripts": false,
61
+ "hasReferences": true,
62
+ "hasAssets": false,
63
+ "hasTests": true
64
+ },
45
65
  {
46
66
  "name": "keel",
47
67
  "directory": "keel",