@slamb2k/mad-skills 2.0.55 → 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/dock/SKILL.md +25 -0
- package/skills/dock/references/hardening.md +104 -0
- package/skills/dock/references/pipeline-templates.md +139 -212
- package/skills/dock/tests/evals.json +10 -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 +24 -4
|
@@ -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,
|
|
@@ -36,7 +36,27 @@
|
|
|
36
36
|
"name": "dock",
|
|
37
37
|
"directory": "dock",
|
|
38
38
|
"description": ">- Generate container-based release pipelines that build once and promote immutable artifacts through environments (dev → staging → prod). Detects your stack, interviews for infrastructure choices, then outputs deterministic CI/CD files (Dockerfile, workflows, deployment manifests) that run without an LLM. Use when setting up deployment pipelines, containerizing an app, creating release workflows, or connecting CI to container-friendly infrastructure (Azure Container Apps, AWS Fargate, Google Cloud Run, Kubernetes, Dokku, Coolify, CapRover, etc.).",
|
|
39
|
-
"lines":
|
|
39
|
+
"lines": 457,
|
|
40
|
+
"hasScripts": false,
|
|
41
|
+
"hasReferences": true,
|
|
42
|
+
"hasAssets": false,
|
|
43
|
+
"hasTests": true
|
|
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,
|
|
40
60
|
"hasScripts": false,
|
|
41
61
|
"hasReferences": true,
|
|
42
62
|
"hasAssets": false,
|