@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.
- package/.claude-plugin/plugin.json +1 -1
- package/hooks/hooks.json +4 -1
- package/package.json +1 -1
- package/skills/build/SKILL.md +64 -0
- package/skills/handover/SKILL.md +164 -0
- package/skills/handover/references/handover-template.md +89 -0
- package/skills/handover/scripts/handover.sh +71 -0
- package/skills/handover/tests/evals.json +35 -0
- package/skills/hoist/SKILL.md +89 -0
- package/skills/hoist/references/hardening.md +62 -0
- package/skills/hoist/references/interview-guide.md +28 -0
- package/skills/hoist/references/release-templates.md +136 -0
- package/skills/hoist/references/setup-guides.md +30 -0
- package/skills/hoist/tests/evals.json +36 -0
- package/skills/manifest.json +23 -3
package/hooks/hooks.json
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
"hooks": {
|
|
3
3
|
"SessionStart": [{
|
|
4
4
|
"matcher": "startup|clear|compact",
|
|
5
|
-
"hooks": [
|
|
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
package/skills/build/SKILL.md
CHANGED
|
@@ -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
|
+
]
|
package/skills/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-07-
|
|
3
|
-
"count":
|
|
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":
|
|
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",
|