opencode-skills-collection 4.0.47 → 4.0.49

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.
Files changed (63) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +11 -2
  2. package/bundled-skills/agent-qa-authoring/SKILL.md +3 -1
  3. package/bundled-skills/agy-delegate/SKILL.md +1 -1
  4. package/bundled-skills/aider-delegate/SKILL.md +1 -1
  5. package/bundled-skills/api-rate-limit-handler/SKILL.md +1 -1
  6. package/bundled-skills/atlas-cloud-media/SKILL.md +52 -18
  7. package/bundled-skills/babysit-pr/SKILL.md +1 -1
  8. package/bundled-skills/boost-asio-pro/references/pre-cpp20.md +8 -1
  9. package/bundled-skills/check-identity-pack/SKILL.md +88 -0
  10. package/bundled-skills/claude-delegate/SKILL.md +1 -1
  11. package/bundled-skills/cline-delegate/SKILL.md +1 -1
  12. package/bundled-skills/codex-delegate/SKILL.md +1 -1
  13. package/bundled-skills/commandcode-delegate/SKILL.md +1 -1
  14. package/bundled-skills/copilot-delegate/SKILL.md +1 -1
  15. package/bundled-skills/cursor-delegate/SKILL.md +1 -1
  16. package/bundled-skills/detect-ai-text/SKILL.md +91 -0
  17. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  18. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  19. package/bundled-skills/docs/maintainers/repo-growth-seo.md +1 -1
  20. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  21. package/bundled-skills/docs/users/aas-core.md +1 -1
  22. package/bundled-skills/docs/users/bundles.md +1 -1
  23. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  24. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  25. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  26. package/bundled-skills/docs/users/usage.md +3 -3
  27. package/bundled-skills/docs/users/visual-guide.md +4 -4
  28. package/bundled-skills/extract-document-data/SKILL.md +99 -0
  29. package/bundled-skills/falsify/SKILL.md +18 -1
  30. package/bundled-skills/find-matching-tenders/SKILL.md +100 -0
  31. package/bundled-skills/graceful-shutdown/SKILL.md +76 -70
  32. package/bundled-skills/grok-delegate/SKILL.md +1 -1
  33. package/bundled-skills/inngest/SKILL.md +2 -0
  34. package/bundled-skills/kimi-delegate/SKILL.md +1 -1
  35. package/bundled-skills/liuguang-banlan-ui/SKILL.md +6 -4
  36. package/bundled-skills/liuguang-banlan-ui/scripts/manifest_parser.py +178 -0
  37. package/bundled-skills/liuguang-banlan-ui/scripts/measure_preview.py +14 -17
  38. package/bundled-skills/liuguang-banlan-ui/scripts/validate_manifest.py +12 -16
  39. package/bundled-skills/lovable-cleanup/SKILL.md +32 -6
  40. package/bundled-skills/lovable-cleanup/references/favicon-vercel-cleanup.md +106 -0
  41. package/bundled-skills/lovable-cleanup/scripts/write-transparent-favicon.js +88 -0
  42. package/bundled-skills/multi-source-search/scripts/validate_report.py +5 -0
  43. package/bundled-skills/omp-delegate/SKILL.md +1 -1
  44. package/bundled-skills/opencode-delegate/SKILL.md +1 -1
  45. package/bundled-skills/pentest-tools/references/pentest-ai-agents-matrix.md +8 -5
  46. package/bundled-skills/pi-delegate/SKILL.md +1 -1
  47. package/bundled-skills/prompt-caching/SKILL.md +3 -1
  48. package/bundled-skills/qoder-delegate/SKILL.md +1 -1
  49. package/bundled-skills/screen-adverse-media/SKILL.md +100 -0
  50. package/bundled-skills/slideops/SKILL.md +201 -0
  51. package/bundled-skills/trigger-dev/SKILL.md +2 -0
  52. package/bundled-skills/unsloth-finetuning/SKILL.md +45 -2
  53. package/bundled-skills/upstash-qstash/SKILL.md +1 -1
  54. package/bundled-skills/upstash-ratelimit/SKILL.md +186 -0
  55. package/bundled-skills/upstash-redis/SKILL.md +156 -0
  56. package/bundled-skills/verify-citations/SKILL.md +88 -0
  57. package/bundled-skills/verify-document/SKILL.md +94 -0
  58. package/bundled-skills/vibe-delegate/SKILL.md +1 -1
  59. package/bundled-skills/warp-delegate/SKILL.md +1 -1
  60. package/bundled-skills/zcode-delegate/SKILL.md +1 -1
  61. package/package.json +1 -1
  62. package/skills_index.json +347 -54
  63. package/bundled-skills/ui-slop-score/SKILL.md +0 -80
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: screen-adverse-media
3
+ description: Screen a person or organisation for adverse media coverage, PEP status, and sanctions exposure — corroboration-gated, returns "review" never "guilty". Use when the user asks to screen someone before onboarding, partnership, or investment; for AML/CTF flows; or for ongoing counterparty monitoring.
4
+ category: document-verification
5
+ risk: critical
6
+ source: community
7
+ source_repo: Sketchjar/stipple-agent-skills
8
+ source_type: community
9
+ date_added: "2026-08-31"
10
+ author: Sketchjar
11
+ tags: [document-verification, fact-checking, stipple, authenticity]
12
+ tools: [claude, cursor, gemini, codex]
13
+ license: "Apache-2.0"
14
+ license_source: "https://github.com/Sketchjar/stipple-agent-skills/blob/main/LICENSE"
15
+ ---
16
+
17
+ # Screen Adverse Media
18
+
19
+ Screen a person or organisation for adverse media coverage, PEP (Politically Exposed Person) status, and sanctions exposure. Every hit is **corroboration-gated**: the screen returns "review", never "guilty", and "nothing found" is never a clean record. Uses the Stipple API (free anonymous tier).
20
+
21
+ ## When to use
22
+
23
+ - AML/CTF onboarding (Tranche 2 reforms make this mandatory for more Australian businesses)
24
+ - Vendor/supplier due diligence before signing
25
+ - Investor or LP vetting
26
+ - Ongoing counterparty monitoring (re-run periodically, compare warrant IDs)
27
+
28
+ ## Instructions
29
+
30
+ 1. **Get the target.** Name of the person or organisation. For document-based screening, a PDF/image of their ID or company extract can also be submitted.
31
+
32
+ 2. **Run the screen.**
33
+
34
+ Name-based (via MCP — the REST intake is document-based):
35
+ ```bash
36
+ # Via any MCP client pointed at https://www.stipple.sh/mcp:
37
+ # tool: screen_adverse_media
38
+ # args: {"name": "John Citizen", "entity_type": "person"}
39
+ ```
40
+
41
+ Document-based (REST — screens the person/org named in the uploaded document):
42
+ ```bash
43
+ curl -X POST https://www.stipple.sh/v1/adverse-media \
44
+ -F "file=@company-extract.pdf" \
45
+ -H "Authorization: Bearer $STIPPLE_API_KEY"
46
+ ```
47
+
48
+ 3. **Interpret the response.**
49
+
50
+ - `rating` — the overall screening result ("review", "clear", etc.)
51
+ - `hits[]` — adverse media articles: date, title, source, URL, summary
52
+ - `pep[]` — PEP signals (empty = none found)
53
+ - `sanctions[]` — sanctions list signals (empty = none found)
54
+
55
+ 4. **Report with the right framing.** Non-negotiable framing rules:
56
+
57
+ | Finding | Correct framing |
58
+ |---|---|
59
+ | Hits found | "Review recommended — see articles below" (never "guilty") |
60
+ | Nothing found | "No corroborated adverse media found — this is NOT a clean record; coverage is bounded by the source list" |
61
+ | PEP signal | "PEP status identified — enhanced due diligence may apply" |
62
+
63
+ 5. **Contextualize.** Every hit is corroborated across sources before inclusion — but the screen is the start of human review, not the end of it. Date-range and source-coverage limitations are real.
64
+
65
+ ## Output format
66
+
67
+ ```
68
+ screening rating: review
69
+
70
+ adverse media hits:
71
+ - [2025-11-02] Court action over unpaid supplier debts
72
+ source: The Age https://...
73
+ - [2024-06-18] ASIC disqualification
74
+ source: ASIC media releases https://...
75
+
76
+ PEP signals: 0
77
+ sanctions list signals: 0
78
+
79
+ This screen returns "review", never "guilty" — every hit is corroboration-gated.
80
+ ```
81
+
82
+ ## Limitations and Safety
83
+
84
+ - Screening processes personal data and potentially damaging allegations through a
85
+ hosted third party. Confirm a lawful purpose, obtain any required approval, send
86
+ only the minimum identifiers needed, and verify current retention, residency,
87
+ access, and deletion terms before transmission.
88
+ - Name matches, PEP signals, sanctions hits, and media reports can be incomplete,
89
+ stale, misattributed, or false. Corroborate every consequential result with the
90
+ original source and authoritative registers; never publish an allegation as fact.
91
+ - This is not a legal AML/CTF determination. A qualified human reviewer must resolve
92
+ identity ambiguity, document the reasoning, and provide an appropriate correction
93
+ or appeal path before rejecting or restricting a person or organization.
94
+
95
+ ## Notes
96
+
97
+ - Costs 3 credits per screen; free weekly allowance applies
98
+ - For AML flows, pair with `check-identity-pack` (identity) and `verify-document` (document genuineness)
99
+ - "Nothing found" ≠ "clean record" — always state this in reports
100
+ - Free key at https://www.stipple.sh for metering beyond the anonymous allowance
@@ -0,0 +1,201 @@
1
+ ---
2
+ name: slideops
3
+ description: "Turn a repository into a cited HTML slide deck and detect the day it drifts from the code. Citations record file, lines, and hash; a stdlib check reports CURRENT, MOVED, or CHANGED."
4
+ category: content
5
+ risk: critical
6
+ source: community
7
+ source_repo: glukicov/slideops
8
+ source_type: community
9
+ date_added: "2026-08-31"
10
+ author: glukicov
11
+ tags: [slides, presentations, documentation, docs-as-code, drift-detection, citations, html]
12
+ tools: [claude-code, codex-cli, copilot, opencode]
13
+ license: "MIT"
14
+ license_source: "https://github.com/glukicov/slideops/blob/main/LICENSE"
15
+ ---
16
+
17
+ # SlideOps: slides from a repo, that tell you when they go stale
18
+
19
+ > **Catalog copy, frozen at v1.0.0.** The canonical source is
20
+ > [glukicov/slideops](https://github.com/glukicov/slideops), which also carries the deck
21
+ > template, the two citation scripts, the reference docs, and the companion
22
+ > `slides-to-pdf` skill. Install from there; this page summarizes the workflow.
23
+
24
+ ## Overview
25
+
26
+ SlideOps has two jobs, and the second one is the point. **Build**: turn a repository into
27
+ a single self-contained HTML slide deck whose every claim came from the code, not from a
28
+ model's impression of the code. **Keep in sync**: make that deck able to prove, months
29
+ later, whether it still matches the repository.
30
+
31
+ The mechanism joining them is a citation. Every quoted snippet records the file, the line
32
+ range, and a hash of those source lines at build time, and the deck records the commit it
33
+ was built from. "Are these slides still accurate?" becomes a command instead of a
34
+ re-read: a standard-library Python script diffs each citation against the current code
35
+ and reports `CURRENT`, `MOVED`, `CHANGED`, or `MISSING`. No model, no network, no tokens,
36
+ milliseconds to run.
37
+
38
+ ## When to Use This Skill
39
+
40
+ - Use when the user asks for slides, a slide deck, or a presentation about a code
41
+ repository, one of its subsystems, a feature, or its recent changes: "make slides",
42
+ "overview deck", "team update slides", "HTML slides for this repo".
43
+ - Use when the user asks whether an existing deck still matches the code, or wants one
44
+ rechecked, refreshed, or kept in sync: "is this deck still accurate", "check the
45
+ slides against the code", "these docs are stale".
46
+ - Use when the user wants deck freshness wired into CI, a pull request check, or an
47
+ agent hook: "fail the build when the deck stops matching the code".
48
+ - Do **not** use for slide decks about anything other than a codebase (a sales deck, a
49
+ lecture); the citation mechanism assumes a git repository as the source of truth.
50
+
51
+ ## How It Works
52
+
53
+ ### Step 1: Install from the canonical repo
54
+
55
+ In Claude Code, as a plugin (both skills, background updates):
56
+
57
+ ```text
58
+ /plugin marketplace add glukicov/slideops
59
+ /plugin install slideops@slideops
60
+ ```
61
+
62
+ Or for Codex CLI, Copilot CLI, and OpenCode, one installer covers all of them:
63
+
64
+ ```bash
65
+ git clone https://github.com/glukicov/slideops && cd slideops
66
+ git checkout ba43e89bc7936649be36a1796a62203f704f8c60 # the v1.0.0 release commit
67
+ ./install.sh
68
+ ```
69
+
70
+ The checkout pins the exact commit this catalog copy froze at, which is what a reader
71
+ can verify independently. (The canonical repo also blocks retargeting of `v*` tags with
72
+ an active tag ruleset, but a SHA does not ask you to trust that.) `install.sh` symlinks
73
+ the two skills into `~/.claude/skills` (read by Claude Code and OpenCode) and
74
+ `~/.agents/skills` (read by Codex CLI and Copilot CLI).
75
+
76
+ ### Step 2: Build a deck
77
+
78
+ The skill walks a fixed pipeline: a two-minute repo scan, one compact intake (topic,
79
+ audience, length, theme, scope, extras), an outline checkpoint before any HTML is
80
+ written, then slide-by-slide construction from a verified template. Every snippet is
81
+ cited as it is written. Run the citation script from inside the repository being
82
+ presented, via its installed path (an agent resolves `scripts/` against the skill's own
83
+ directory automatically; the paths below are for running it yourself after
84
+ `install.sh`):
85
+
86
+ ```bash
87
+ python3 ~/.agents/skills/slideops/scripts/cite.py app/main.py:40-58 --repo . --snippet # prints data-src + data-sha256
88
+ python3 ~/.agents/skills/slideops/scripts/cite.py --stamp deck.html --repo . # stamps the build commit
89
+ ```
90
+
91
+ `--repo` always points at the repository the deck is about, never at the SlideOps
92
+ checkout.
93
+
94
+ Every slide is then rendered with headless Chrome and visually verified before the deck
95
+ is considered done.
96
+
97
+ ### Step 3: Check it later, for free
98
+
99
+ From inside the repository being presented, same path convention as Step 2:
100
+
101
+ ```bash
102
+ python3 ~/.agents/skills/slideops/scripts/check.py docs/slides/ --repo .
103
+ ```
104
+
105
+ Real output, from the demo deck that ships with the skill:
106
+
107
+ ```text
108
+ Deck: skill-demo.html
109
+ Built: commit=179bbdb date=2026-08-28 repo=slideops
110
+
111
+ slide 9 THEMING skills/slideops/assets/template.html:22-45 CURRENT
112
+ slide 14 MERMAID skills/slideops/references/diagrams.md:55-59 CURRENT
113
+
114
+ 2 current, 0 stale, 2 cited in total.
115
+ ```
116
+
117
+ `MOVED` means only line numbers shifted (update two attributes, leave the prose).
118
+ `CHANGED` means the quoted code was edited (read the diff, decide whether the slide's
119
+ claim survived). `MISSING` means the file is gone (the slide is probably obsolete). The
120
+ `--json` flag emits a complete repair brief per stale citation, so an agent can fix
121
+ drift without re-reading the repository.
122
+
123
+ ## Examples
124
+
125
+ ### Example 1: New deck
126
+
127
+ ```text
128
+ User: make slides about this repo
129
+ Agent: [scans repo, proposes 3-4 concrete topics with a "why now" each,
130
+ asks one compact intake, shows an outline, then builds and
131
+ visually verifies a cited HTML deck at docs/slides/]
132
+ ```
133
+
134
+ ### Example 2: Freshness check in CI
135
+
136
+ ```bash
137
+ python3 tools/slideops-check.py docs/slides/ --repo . --exit-zero # report-only PR annotation
138
+ ```
139
+
140
+ The canonical repo's `references/automation.md` has the PR-check workflow, advisory hook
141
+ variants, and a delegated-refresh recipe. `check.py` is one dependency-free file, meant
142
+ to be vendored into the deck's own repo.
143
+
144
+ ## Best Practices
145
+
146
+ - ✅ Cite with `cite.py`, never by hand: a hand-computed hash silently reports `CHANGED`
147
+ months later and nobody can tell whether the code moved or the build was sloppy.
148
+ - ✅ Repair a drifted deck; do not rebuild it. Fix only the slides whose citations went
149
+ stale, then re-stamp.
150
+ - ✅ Automate the check for evergreen decks (onboarding, architecture); leave snapshots
151
+ (sprint updates, conference talks) frozen deliberately.
152
+ - ❌ Do not run `check.py` against a PDF export: citations live in the HTML, so the PDF
153
+ reports "No citations found in this deck".
154
+ - ❌ Do not block every commit on the check. Report-only on pull requests first; a docs
155
+ gate on the fast path trains people to pass `--no-verify`.
156
+
157
+ ## Limitations
158
+
159
+ - Needs a headless Chrome or Chromium binary (Playwright cache or system install) for
160
+ the visual verification pass, and Python 3 for the citation scripts.
161
+ - Works offline except two opt-ins: Mermaid diagrams (a one-time `npx` download) and
162
+ brand-color extraction from a live style guide.
163
+ - The check verifies quoted snippets against the code; it cannot verify prose claims
164
+ that cite nothing.
165
+ - Drift detection assumes the deck and the code share a git repository.
166
+
167
+ ## Security & Safety Notes
168
+
169
+ - Ask before cloning the upstream repository, running `install.sh`, creating skill
170
+ symlinks in the user's home directory, downloading an optional `npx` package, or
171
+ writing deck output. Show the exact pinned commit and destination paths first, and
172
+ preserve any existing skill entries instead of overwriting them silently.
173
+ - The citation scripts are standard-library-only Python: no dependencies, no network,
174
+ no tokens.
175
+ - The skill declares no `allowed-tools`, deliberately: the host agent's own permission
176
+ model stays in charge, and headless Chrome keeps its sandbox.
177
+ - The skill carries an explicit confidentiality rule for deck content: never read or
178
+ quote secrets, keys, `.env` files, production logs, or customer data; redact internal
179
+ hostnames and identifiers; and finish with a redaction scan of the rendered slides,
180
+ because decks are documents that leave the repository.
181
+ - File writes are limited to the deck output folder (default `docs/slides/`) plus its
182
+ companion README.
183
+
184
+ ## Common Pitfalls
185
+
186
+ - **Problem:** `check.py` on an exported PDF reports no citations.
187
+ **Solution:** Run it against the HTML deck; the PDF is a derived artifact from the
188
+ companion `slides-to-pdf` skill.
189
+ - **Problem:** A freshly built deck already reports `CHANGED`.
190
+ **Solution:** That is a build defect, not a future problem: a snippet was quoted and
191
+ then edited, or a hash was hand-computed. Re-cite with `cite.py` before shipping.
192
+ - **Problem:** Chrome is not found on the verification step.
193
+ **Solution:** The canonical repo's `references/verification.md` has the cross-platform
194
+ discovery recipe (Playwright cache first, then system installs).
195
+
196
+ ## Related Skills
197
+
198
+ - `slides-to-pdf` (same canonical repo): screenshots every slide at 2x, prints a
199
+ page-per-slide PDF, and verifies the result by rendering the PDF back to images.
200
+ - `@2slides-ppt-generator`: API-driven deck generation from text or documents; use it
201
+ when the source material is not a code repository.
@@ -38,6 +38,7 @@ execution with excellent developer experience and TypeScript-first design.
38
38
  ## Scope
39
39
 
40
40
  - redis-queues -> bullmq-specialist
41
+ - serverless-queues -> upstash-qstash
41
42
  - pure-event-driven -> inngest
42
43
  - workflow-orchestration -> temporal-craftsman
43
44
  - infrastructure -> infra-architect
@@ -891,6 +892,7 @@ Fix action: Batch items and use fewer waits, or split into subtasks
891
892
  ### Delegation Triggers
892
893
 
893
894
  - redis|bullmq|traditional queue -> bullmq-specialist (Need Redis-backed queues instead of managed service)
895
+ - serverless queue|http queue|no workers -> upstash-qstash (Need HTTP-delivered queues and schedules without a worker runtime)
894
896
  - vercel|deployment|serverless -> vercel-deployment (Trigger.dev needs deployment config)
895
897
  - database|postgres|supabase -> supabase-backend (Tasks need database access)
896
898
  - openai|anthropic|ai model|llm -> llm-architect (Tasks need AI model integration)
@@ -72,10 +72,20 @@ libraries at import time; importing them first silently disables the optimizatio
72
72
 
73
73
  ```python
74
74
  import unsloth # must be first
75
+ import os
76
+ import re
75
77
  from unsloth import FastLanguageModel
76
78
 
79
+ def reviewed_revision(variable):
80
+ revision = os.environ.get(variable, "")
81
+ if re.fullmatch(r"[0-9a-fA-F]{40}", revision) is None:
82
+ raise RuntimeError(f"{variable} must be a reviewed full 40-character Hub commit SHA")
83
+ return revision.lower()
84
+
85
+ model_revision = reviewed_revision("UNSLOTH_MODEL_REVISION")
77
86
  model, tokenizer = FastLanguageModel.from_pretrained(
78
87
  model_name = "unsloth/Qwen3-8B",
88
+ revision = model_revision,
79
89
  max_seq_length = 2048,
80
90
  load_in_4bit = True,
81
91
  dtype = None, # auto-detects bf16 where supported
@@ -87,6 +97,9 @@ Pick the loader that matches the modality: `FastLanguageModel` for text-only cau
87
97
 
88
98
  The `unsloth/` Hub namespace holds pre-quantized copies that download faster and skip a local
89
99
  quantization pass. Upstream repos such as `Qwen/` or `meta-llama/` work identically.
100
+ Before setting `UNSLOTH_MODEL_REVISION`, inspect that exact Hub commit and obtain approval for the
101
+ download. Record the repository and full revision with the run; never substitute a branch, tag,
102
+ range, or moving default.
90
103
 
91
104
  ### Step 3: Fix the chat template before training
92
105
 
@@ -194,20 +207,35 @@ cannot be cleanly re-quantized afterwards.
194
207
 
195
208
  ```python
196
209
  import unsloth
210
+ import os
211
+ import re
197
212
  from unsloth import FastLanguageModel
198
213
  from unsloth.chat_templates import get_chat_template, train_on_responses_only
199
214
  from datasets import load_dataset
200
215
  from trl import SFTTrainer, SFTConfig
201
216
 
217
+ def reviewed_revision(variable):
218
+ revision = os.environ.get(variable, "")
219
+ if re.fullmatch(r"[0-9a-fA-F]{40}", revision) is None:
220
+ raise RuntimeError(f"{variable} must be a reviewed full 40-character Hub commit SHA")
221
+ return revision.lower()
222
+
223
+ model_revision = reviewed_revision("UNSLOTH_MODEL_REVISION")
224
+ dataset_revision = reviewed_revision("UNSLOTH_DATASET_REVISION")
202
225
  model, tokenizer = FastLanguageModel.from_pretrained(
203
226
  model_name = "unsloth/Qwen3-8B",
227
+ revision = model_revision,
204
228
  max_seq_length = 2048,
205
229
  load_in_4bit = True,
206
230
  )
207
231
  model = FastLanguageModel.get_peft_model(model, r = 16, lora_alpha = 16)
208
232
 
209
233
  tokenizer = get_chat_template(tokenizer, chat_template = "qwen3")
210
- dataset = load_dataset("mlabonne/FineTome-100k", split = "train[:5000]")
234
+ dataset = load_dataset(
235
+ "mlabonne/FineTome-100k",
236
+ revision = dataset_revision,
237
+ split = "train[:5000]",
238
+ )
211
239
 
212
240
  trainer = SFTTrainer(
213
241
  model = model,
@@ -239,11 +267,21 @@ Load with `fast_inference=True` to route sampling through vLLM in the same proce
239
267
 
240
268
  ```python
241
269
  import unsloth
270
+ import os
271
+ import re
242
272
  from unsloth import FastLanguageModel
243
273
  from trl import GRPOTrainer, GRPOConfig
244
274
 
275
+ def reviewed_revision(variable):
276
+ revision = os.environ.get(variable, "")
277
+ if re.fullmatch(r"[0-9a-fA-F]{40}", revision) is None:
278
+ raise RuntimeError(f"{variable} must be a reviewed full 40-character Hub commit SHA")
279
+ return revision.lower()
280
+
281
+ model_revision = reviewed_revision("UNSLOTH_MODEL_REVISION")
245
282
  model, tokenizer = FastLanguageModel.from_pretrained(
246
283
  model_name = "unsloth/Qwen3-4B",
284
+ revision = model_revision,
247
285
  max_seq_length = 1024,
248
286
  load_in_4bit = True,
249
287
  fast_inference = True, # vLLM sampling backend
@@ -307,8 +345,13 @@ GRPO learning rates sit roughly two orders of magnitude below SFT. Reward functi
307
345
  committed token grants write access to every model the account owns.
308
346
  - Fine-tuning reproduces the training data's content and biases in the weights. Confirm the
309
347
  dataset is licensed for training and free of secrets before starting.
348
+ - Pin every Hub model and dataset to a reviewed full commit SHA, obtain approval before changing
349
+ either revision, and record both values with the training artifact. Prefer the verified local
350
+ cache for repeat runs instead of re-resolving network defaults.
310
351
  - GGUF export builds llama.cpp from source on first use, compiling third-party code and
311
- requiring network access. Expect it to be slow and to need a working toolchain.
352
+ requiring network access. Before the first export, identify and review the exact llama.cpp
353
+ revision that will be built; do not permit an unattended moving-revision fetch. Prefer a
354
+ user-approved, full-commit-pinned local toolchain and cache.
312
355
  - Unsloth is dual-licensed: the core package is Apache-2.0, while optional components such as
313
356
  the Studio UI are AGPL-3.0. Check a component's license before redistributing it.
314
357
 
@@ -931,7 +931,7 @@ Workflow:
931
931
 
932
932
  ## Related Skills
933
933
 
934
- Works well with: `vercel-deployment`, `nextjs-app-router`, `redis-specialist`, `email-systems`, `supabase-backend`, `cloudflare-workers`
934
+ Works well with: `upstash-redis`, `upstash-ratelimit`, `vercel-deployment`, `nextjs-app-router`, `redis-specialist`, `email-systems`, `supabase-backend`, `cloudflare-workers`
935
935
 
936
936
  ## When to Use
937
937
  - User mentions or implies: qstash
@@ -0,0 +1,186 @@
1
+ ---
2
+ name: upstash-ratelimit
3
+ description: "Add rate limiting to API routes, middleware, and edge functions with @upstash/ratelimit: sliding window, fixed window, and token bucket backed by Upstash Redis."
4
+ category: backend
5
+ risk: critical
6
+ source: self
7
+ source_type: self
8
+ date_added: "2026-08-31"
9
+ author: CahidArda
10
+ tags: [upstash, rate-limiting, redis, serverless, edge, middleware, 429]
11
+ tools: [claude, codex, cursor, gemini]
12
+ ---
13
+
14
+ # Upstash Ratelimit
15
+
16
+ ## Overview
17
+
18
+ `@upstash/ratelimit` implements distributed rate limiting on top of Upstash
19
+ Redis. Because state lives in Redis, every instance of a serverless function
20
+ or edge worker shares the same counters, which an in-memory limiter cannot
21
+ do. It ships three algorithms (fixed window, sliding window, token bucket),
22
+ per-identifier keys, optional in-memory blocking of already-limited
23
+ identifiers, and optional analytics.
24
+
25
+ ## When to Use This Skill
26
+
27
+ - Use when the user needs to limit requests per IP, user, API key, or tenant
28
+ across multiple serverless instances or regions.
29
+ - Use when protecting login, signup, form, webhook, or LLM endpoints from
30
+ abuse and returning `429 Too Many Requests`.
31
+ - Use when choosing between fixed window, sliding window, and token bucket.
32
+ - Do not use for client-side retry/backoff against a third-party API's limits;
33
+ see `api-rate-limit-handler`.
34
+ - Do not use for a single long-running process with no shared state; an
35
+ in-memory limiter is simpler there.
36
+
37
+ ## How It Works
38
+
39
+ ### Step 1: Install and configure
40
+
41
+ ```bash
42
+ npm install @upstash/ratelimit @upstash/redis
43
+ ```
44
+
45
+ Set `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` in the environment.
46
+
47
+ ### Step 2: Create the limiter once, outside the handler
48
+
49
+ ```typescript
50
+ import { Ratelimit } from "@upstash/ratelimit";
51
+ import { Redis } from "@upstash/redis";
52
+
53
+ export const ratelimit = new Ratelimit({
54
+ redis: Redis.fromEnv(),
55
+ limiter: Ratelimit.slidingWindow(10, "10 s"), // 10 requests per 10 seconds
56
+ prefix: "rl:api",
57
+ analytics: true,
58
+ });
59
+ ```
60
+
61
+ Constructing the limiter at module scope lets the built-in ephemeral cache
62
+ short-circuit blocked identifiers without a Redis call.
63
+
64
+ ### Step 3: Call `limit()` with a stable identifier
65
+
66
+ ```typescript
67
+ const { success, limit, remaining, reset, pending } = await ratelimit.limit(userId);
68
+ ```
69
+
70
+ `success` is `false` when the identifier is over its limit. `reset` is a Unix
71
+ timestamp in milliseconds. `pending` is a promise for background work
72
+ (analytics, multi-region sync); await it or pass it to `waitUntil` on edge
73
+ runtimes so the function is not frozen before it completes.
74
+
75
+ ## Examples
76
+
77
+ ### Example 1: Next.js middleware returning 429
78
+
79
+ ```typescript
80
+ import { Ratelimit } from "@upstash/ratelimit";
81
+ import { Redis } from "@upstash/redis";
82
+ import { NextResponse, type NextRequest } from "next/server";
83
+
84
+ const ratelimit = new Ratelimit({
85
+ redis: Redis.fromEnv(),
86
+ limiter: Ratelimit.slidingWindow(20, "1 m"),
87
+ });
88
+
89
+ export async function middleware(request: NextRequest) {
90
+ const ip = request.headers.get("x-forwarded-for") ?? "anonymous";
91
+ const { success, limit, remaining, reset } = await ratelimit.limit(ip);
92
+
93
+ if (!success) {
94
+ return new NextResponse("Too Many Requests", {
95
+ status: 429,
96
+ headers: {
97
+ "X-RateLimit-Limit": String(limit),
98
+ "X-RateLimit-Remaining": String(remaining),
99
+ "X-RateLimit-Reset": String(reset),
100
+ "Retry-After": String(Math.ceil((reset - Date.now()) / 1000)),
101
+ },
102
+ });
103
+ }
104
+ return NextResponse.next();
105
+ }
106
+
107
+ export const config = { matcher: "/api/:path*" };
108
+ ```
109
+
110
+ ### Example 2: Token bucket with per-plan limits
111
+
112
+ ```typescript
113
+ const limiters = {
114
+ free: new Ratelimit({
115
+ redis: Redis.fromEnv(),
116
+ prefix: "rl:free",
117
+ limiter: Ratelimit.tokenBucket(5, "10 s", 10), // refill 5 per 10 s, burst 10
118
+ }),
119
+ pro: new Ratelimit({
120
+ redis: Redis.fromEnv(),
121
+ prefix: "rl:pro",
122
+ limiter: Ratelimit.tokenBucket(50, "10 s", 100),
123
+ }),
124
+ };
125
+
126
+ const { success } = await limiters[plan].limit(apiKey);
127
+ ```
128
+
129
+ ## Best Practices
130
+
131
+ - ✅ Use a stable, low-cardinality identifier (user id, API key, tenant) where
132
+ possible; fall back to IP only for anonymous traffic.
133
+ - ✅ Set a distinct `prefix` per endpoint or plan so limits do not collide.
134
+ - ✅ Return `Retry-After` and `X-RateLimit-*` headers with 429 responses.
135
+ - ✅ Prefer `slidingWindow` for most APIs; use `tokenBucket` when short bursts
136
+ are acceptable; use `fixedWindow` when the lowest Redis cost matters.
137
+ - ❌ Don't construct a new `Ratelimit` inside the request handler.
138
+ - ❌ Don't rely on `pending` completing on its own in edge runtimes.
139
+ - ❌ Don't rate limit by `x-forwarded-for` without validating it is set by
140
+ your proxy; clients can spoof it otherwise.
141
+
142
+ ## Limitations
143
+
144
+ - Requires an Upstash Redis database; it does not work with other Redis
145
+ servers or without network access.
146
+ - Each `limit()` call is at least one HTTP round trip to Redis, so it adds
147
+ latency to every request it guards.
148
+ - Sliding window is an approximation that assumes an even spread of requests
149
+ in the previous window; it is not an exact log.
150
+ - `MultiRegionRatelimit` trades strict accuracy for lower latency and does
151
+ not support the token bucket algorithm.
152
+ - If Redis is unreachable, the default `timeout` (5 s) lets requests through
153
+ (`reason: "timeout"`); this fails open, not closed.
154
+ - This skill does not replace environment-specific validation, testing, or
155
+ expert review.
156
+
157
+ ## Security & Safety Notes
158
+
159
+ - Rate limiting is one layer of abuse protection, not authentication. Pair it
160
+ with auth and input validation.
161
+ - The Redis token grants full database access; keep it server-side.
162
+ - Changing limits in production can lock out legitimate users. Confirm the
163
+ numbers with the user before deploying stricter limits.
164
+
165
+ ## Common Pitfalls
166
+
167
+ - **Problem:** Every request is allowed even after the limit.
168
+ **Solution:** Each identifier must be the same string across requests;
169
+ check that the identifier is not `undefined` or a fresh random value.
170
+ - **Problem:** Analytics are empty on Vercel Edge or Cloudflare Workers.
171
+ **Solution:** Pass `pending` to `waitUntil` (`ctx.waitUntil(pending)`) so
172
+ the background request is not cancelled when the response is sent.
173
+
174
+ ## Related Skills
175
+
176
+ - `@upstash-redis` - The client this package uses for storage.
177
+ - `@api-rate-limit-handler` - Client-side backoff and retry when you are the
178
+ one being rate limited.
179
+ - `@upstash-qstash` - Queue and smooth traffic to downstream services instead
180
+ of rejecting it.
181
+
182
+ ## Additional Resources
183
+
184
+ - [Upstash Ratelimit documentation](https://upstash.com/docs/redis/sdks/ratelimit-ts/overview)
185
+ - [@upstash/ratelimit on GitHub](https://github.com/upstash/ratelimit-js)
186
+ - [Algorithms guide](https://upstash.com/docs/redis/sdks/ratelimit-ts/algorithms)