@ericrisco/rsc 0.1.57 → 0.1.59

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/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.57",
2
+ "version": "0.1.59",
3
3
  "counts": {
4
4
  "skills": 258
5
5
  },
@@ -1930,7 +1930,7 @@
1930
1930
  },
1931
1931
  {
1932
1932
  "id": "gamedev-physics",
1933
- "description": "Use when working with a game engine's physics — rigid bodies, colliders, collision layers/masks, character controllers, joints, forces vs impulses, raycasts/shapecasts, or when physics is unstable. Triggers: \\\"my character falls through the floor\\\", \\\"bullet tunnels through walls at high speed\\\", \\\"rigidbody jitters / vibrates / explodes\\\", \\\"objects that should collide pass through each other\\\", \\\"which collision layer and mask do I set\\\", \\\"kinematic vs dynamic body\\\", \\\"move_and_slide / CharacterBody\\\", \\\"AddForce vs impulse vs setting velocity\\\", \\\"physics in FixedUpdate or _physics_process\\\", \\\"slope and step detection\\\", \\\"trigger / Area overlap not firing\\\", Godot RigidBody/StaticBody/CharacterBody/Area, Unity Rigidbody/Collider/CharacterController, Unreal Chaos/collision presets. NOT rendering, materials, or visual jitter from shaders (use gamedev-shaders); NOT AI navigation, pathfinding, or navmesh (use gamedev-pathing).",
1933
+ "description": "Use when working with a game engine's physics — rigid bodies, colliders, collision layers and masks, character controllers, joints, forces versus impulses, raycasts and shapecasts, or when a simulation is unstable (tunnelling, jitter, missed overlaps). Covers the Godot, Unity and Unreal equivalents. NOT rendering or shader-driven visual jitter (that is `gamedev-shaders`), NOT navigation, pathfinding or navmesh (that is `gamedev-pathing`).",
1934
1934
  "tags": [
1935
1935
  "physics",
1936
1936
  "collision",
@@ -2047,7 +2047,7 @@
2047
2047
  },
2048
2048
  {
2049
2049
  "id": "git-workflow",
2050
- "description": "Use when naming or scoping a branch, writing or fixing a commit message, untangling history (rebase vs merge vs squash), or cutting a versioned release — the portable git-convention layer that works on any repo. Triggers: 'name this branch', 'is this commit message conventional?', 'rebase or merge before the PR?', 'squash these wip commits into one', 'my git log is a mess', 'tag a release', 'write release notes', 'what version should this release be?', 'clean up history before review', 'limpia el historial antes del PR', '¿qué versión le toca a esta release?', 'deja los commits en formato convencional'. Covers Conventional Commits 1.0.0, SemVer tags, branch hygiene, force-push safety, and gh pr/release mechanics. NOT the I'm-done land-it decision and pre-ship checklist (that is ship), NOT setting up an isolated checkout before coding (that is worktrees), NOT CI/CD release automation in GitHub Actions (that is deployment).",
2050
+ "description": "Use when naming or scoping a branch, writing or fixing a commit message, untangling history (rebase versus merge versus squash), or cutting a versioned release — the portable git-convention layer for any repo. Covers Conventional Commits, SemVer tags, branch hygiene, force-push safety and gh pr/release mechanics. NOT the land-it decision and pre-ship checklist (that is `ship`), NOT an isolated checkout before coding (that is `worktrees`), NOT CI/CD release automation (that is `deployment`).",
2051
2051
  "tags": [
2052
2052
  "git",
2053
2053
  "version-control",
@@ -2126,7 +2126,7 @@
2126
2126
  },
2127
2127
  {
2128
2128
  "id": "google-workspace",
2129
- "description": "Use when building server-side automation that reads or writes Gmail, Drive, Calendar, or Sheets against a real Google Workspace account via the official client libraries and a GCP service account — picking the auth mode, scoping OAuth scopes, building the authed client, and debugging 403/429/unauthorized_client errors. Triggers: 'send mail from a service account in a cron', 'unauthorized_client when impersonating a user', 'which Drive scope to upload to a shared drive', 'set up domain-wide delegation client ID', 'getting 403 insufficient permissions from the Sheets API', 'automatizar Gmail con cuenta de servicio sin login del usuario', 'enviar correos desde un script sense login d'usuari'. NOT generic SMTP/marketing/deliverability email (that is email-connector).",
2129
+ "description": "Use when server-side code reads or writes Gmail, Drive, Calendar, or Sheets with a GCP service account and no human in the OAuth loop: picking the auth mode (app-owned vs domain-wide delegation vs keyless), scoping to least privilege, building the authed Node/Python client, staying under per-user quota, and debugging unauthorized_client / 403 / 429. NOT SMTP providers or deliverability (that is `email-connector`), NOT slot-finding and booking UX (that is `calendar-scheduling`).",
2130
2130
  "tags": [
2131
2131
  "google-workspace",
2132
2132
  "gmail-api",
@@ -2235,7 +2235,7 @@
2235
2235
  },
2236
2236
  {
2237
2237
  "id": "htmx",
2238
- "description": "Use when adding interactivity to a server-rendered app (FastAPI/Jinja, Django, Rails, Laravel, Go templates, Express) without adopting a JS framework, wiring hx-get/post/put/delete plus hx-target plus hx-swap plus hx-trigger, returning HTML fragments instead of JSON, doing out-of-band swaps, or building active search, infinite scroll, inline edit, click-to-load, and polling. Triggers: 'swap a server partial into a div on click', 'return an HTML fragment not JSON', 'render a fragment on HX-Request else the full page', 'update the cart count and drawer from one response', 'live search box without React', 'afegir interactivitat a la meva app Django sense muntar un SPA', 'intercambiar un fragmento HTML del servidor', 'buscador en vivo sin SPA'. NOT a client-state SPA with routing/store (that is react / nextjs).",
2238
+ "description": "Use when adding interactivity to a server-rendered app (FastAPI/Jinja, Django, Rails, Laravel, Go templates, Express) without adopting a JS framework — hx-get/post/put/delete with hx-target, hx-swap and hx-trigger, returning HTML fragments instead of JSON, out-of-band swaps, active search, infinite scroll, inline edit and polling. NOT a client-state SPA with routing and a store (that is `react` or `nextjs`).",
2239
2239
  "tags": [
2240
2240
  "htmx",
2241
2241
  "hypermedia",
@@ -2253,7 +2253,7 @@
2253
2253
  },
2254
2254
  {
2255
2255
  "id": "huggingface",
2256
- "description": "Use when running open models or working on the Hugging Face platform: calling a model via the Inference Providers router or InferenceClient, downloading/uploading/versioning repos on the Hub with the hf CLI, deploying a dedicated Inference Endpoint with scale-to-zero, hosting a Gradio Space with ZeroGPU, picking an open model by task/license/size, or loading a model locally with transformers. Triggers: 'call an open model through Hugging Face', 'InferenceClient embeddings', 'hf download/upload', 'write a model card', 'router.huggingface.co', 'my hf-inference serverless call 404s on a 70B model', 'scale-to-zero endpoint', 'ZeroGPU Space', 'desplegar un modelo de Hugging Face con escalado a cero'. NOT serving a model locally on your own machine (that is ollama), NOT renting and operating your own GPU box (that is runpod), NOT generating creative images via a hosted API (that is replicate-images), NOT fine-tuning with trl/peft (that is finetuning), NOT building training datasets (that is training-data).",
2256
+ "description": "Use when running open models or working on the Hugging Face platform — the Inference Providers router or InferenceClient, Hub repos via the hf CLI, a dedicated Inference Endpoint with scale-to-zero, a Gradio Space with ZeroGPU, picking an open model by task/license/size, or loading one locally with transformers. NOT serving locally on your own machine (that is `ollama`), NOT renting your own GPU box (that is `runpod`), NOT hosted creative image APIs (that is `replicate-images`), NOT fine-tuning with trl/peft (that is `finetuning`).",
2257
2257
  "tags": [
2258
2258
  "huggingface",
2259
2259
  "inference-providers",
@@ -2335,7 +2335,7 @@
2335
2335
  },
2336
2336
  {
2337
2337
  "id": "inventory",
2338
- "description": "Use when deciding how much stock to hold and when to reorder it — classifying SKUs, sizing safety stock, setting reorder points and order quantities, and tracking inventory KPIs so a business neither stocks out nor sits on dead stock. Triggers: 'what should my reorder point be', 'how much safety stock', 'run an ABC analysis', 'set up min/max levels', 'should I review weekly or continuously', 'we keep running out of X while sitting on a year of Y', 'too much cash tied up in stock', 'punt de comanda', 'stock de seguretat', 'cuánto stock de seguridad necesito si el proveedor a veces tarda el doble'. NOT raising or negotiating the purchase order itself (that is procurement).",
2338
+ "description": "Use when deciding how much stock to hold and when to reorder it — classifying SKUs, sizing safety stock, setting reorder points and order quantities, and tracking the KPIs that keep a business from either stocking out or sitting on dead stock. NOT raising or negotiating the purchase order itself (that is `procurement`).",
2339
2339
  "tags": [
2340
2340
  "reorder-point",
2341
2341
  "safety-stock",
@@ -2358,7 +2358,7 @@
2358
2358
  },
2359
2359
  {
2360
2360
  "id": "investor-materials",
2361
- "description": "Use when packaging, organizing, or circulating the documents an investor reads OUTSIDE the meeting — setting up or cleaning a data room, writing the investor one-pager/teaser that earns the first meeting, or drafting the recurring monthly/quarterly investor update — symptoms include unnamed dump-folder files, no follow-on warmth, or needing the attachment a cold email carries. Triggers: 'set up our data room', 'what docs do investors expect before diligence', 'write our investor one-pager / teaser', 'draft this month's investor update', 'our data room is a mess, rename and reorganize the files', 'set up a reusable monthly update format', 'sala de datos para inversores', 'actualización mensual a inversores', 'sala de dades / resum d'una pàgina per a inversors'. NOT the slide narrative (that is pitch-deck), NOT the projection spreadsheet (that is financial-model), NOT the round strategy and investor pipeline (that is fundraising).",
2361
+ "description": "Use when packaging or circulating the documents an investor reads outside the meeting — setting up or cleaning a data room, writing the one-pager or teaser that earns the first meeting, or drafting the recurring monthly investor update. NOT the slide narrative (that is `pitch-deck`), NOT the projection spreadsheet (that is `financial-model`), NOT round strategy and the investor pipeline (that is `fundraising`).",
2362
2362
  "tags": [
2363
2363
  "fundraising",
2364
2364
  "data-room",
@@ -2404,7 +2404,7 @@
2404
2404
  },
2405
2405
  {
2406
2406
  "id": "ip-trademark",
2407
- "description": "Use when a non-lawyer operator needs to protect a brand or creative work — clearing and choosing a name/logo, deciding whether and where to register a trademark, using ™/® correctly, knowing what copyright they get for free, or checking whether they actually own work they paid a freelancer for. Triggers: 'can I use this name', 'is this trademark taken', 'when can I put the ® on our logo', 'we paid the freelancer so we own it, right?', 'is our AI-generated logo copyrightable', 'register the trademark in the US or the EU', 'someone copied our content, what can we do', '¿puedo registrar esta marca?', '¿de quién es el copyright del logo?'. NOT drafting the IP-assignment clause itself (that is contracts).",
2407
+ "description": "Use when a non-lawyer operator needs to protect a brand or creative work — clearing and choosing a name or logo, deciding whether and where to register a trademark, using the trademark and registered symbols correctly, knowing what copyright is automatic, or checking whether they own work a freelancer was paid for. NOT drafting the IP-assignment clause itself (that is `contracts`).",
2408
2408
  "tags": [
2409
2409
  "intellectual-property",
2410
2410
  "trademark",
@@ -2422,7 +2422,7 @@
2422
2422
  },
2423
2423
  {
2424
2424
  "id": "java",
2425
- "description": "Use when writing, reviewing, or refactoring modern Java (21+, Java 25 LTS) - records and sealed interfaces as algebraic data types, exhaustive pattern-matching switch over instanceof+cast ladders, virtual-thread (Project Loom) concurrency one-task-per-thread, structured concurrency and ScopedValue replacing ThreadLocal, Stream/Optional/Collector pipelines, compact-constructor validation, parametrized JDBC, and the Maven 3.9 / Gradle 9 build surface against a current JDK. Triggers: \\\"write a Java service\\\", \\\"is this idiomatic Java\\\", \\\"refactor this instanceof ladder\\\", \\\"fetch 500 URLs concurrently\\\", \\\"model this domain with records\\\", .java files, pom.xml, build.gradle, the non-obvious \\\"my ThreadLocal context disappears inside the tasks I submit\\\" (that is ScopedValue), \\\"modela este dominio de pagos con tipos inmutables\\\", \\\"refactoritza aquest switch\\\". NOT Spring framework wiring (that is spring-boot).",
2425
+ "description": "Use when writing, reviewing or refactoring modern Java (21+, 25 LTS) — records and sealed interfaces as algebraic data types, exhaustive pattern-matching switch over instanceof ladders, virtual-thread concurrency, structured concurrency and ScopedValue replacing ThreadLocal, Stream and Optional pipelines, compact-constructor validation, parametrized JDBC, and the Maven/Gradle build surface. NOT Spring framework wiring (that is `spring-boot`).",
2426
2426
  "tags": [
2427
2427
  "java",
2428
2428
  "jvm",
@@ -2462,7 +2462,7 @@
2462
2462
  },
2463
2463
  {
2464
2464
  "id": "kotlin-android",
2465
- "description": "Use when building or fixing a native Android app in Kotlin + Jetpack Compose with the UDF layered architecture (ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe Navigation, Gradle/AGP setup). Triggers: a Compose screen that recomposes every frame or loses state on rotation, wiring ViewModel state into the UI, an offline-first repository, a Hilt DI graph, a Room DAO, build.gradle.kts/version-catalog and AGP/Kotlin floors, 'cómo expongo el estado del ViewModel con StateFlow', 'la pantalla Compose se recompone en cada frame', 'mi app Android pierde el estado al rotar'. NOT shared Android+iOS UI from one Kotlin codebase (that is compose-multiplatform).",
2465
+ "description": "Use when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe Navigation, and the Gradle/AGP surface. NOT shared Android and iOS UI from one Kotlin codebase (that is `compose-multiplatform`).",
2466
2466
  "tags": [
2467
2467
  "kotlin",
2468
2468
  "android",
@@ -2484,7 +2484,7 @@
2484
2484
  },
2485
2485
  {
2486
2486
  "id": "kpi-framework",
2487
- "description": "Use when a team must decide what to measure before building anything — picking one north-star metric, separating leading input drivers from lagging outputs, adding guardrails so a number can't be gamed, or setting a target that isn't arbitrary. Triggers: 'what should we even be measuring', 'we track 40 KPIs and nothing leads anywhere', 'is signups a leading or lagging indicator', 'set an activation target that won't get gamed', 'pick a north star for the product', 'audit our vanity metrics', 'quins KPIs triem per al producte', 'qué métrica norte elegimos'. NOT building the live dashboard that displays them (that is dashboard), NOT instrumenting the events (that is analytics), NOT the recurring board report (that is reporting).",
2487
+ "description": "Use when a team must decide what to measure before building anything — picking one north-star metric, separating leading input drivers from lagging outputs, adding guardrails so a number cannot be gamed, and setting a target that is not arbitrary. NOT the live dashboard that displays them (that is `dashboard`), NOT instrumenting the events (that is `analytics`), NOT the recurring board report (that is `reporting`).",
2488
2488
  "tags": [
2489
2489
  "north-star-metric",
2490
2490
  "leading-vs-lagging",
@@ -2570,7 +2570,7 @@
2570
2570
  },
2571
2571
  {
2572
2572
  "id": "level-design",
2573
- "description": "Use when designing a game level, map, arena, or encounter — laying out a blockout/greybox, fixing pacing that drags or spikes, guiding players without hand-holding, placing secrets and rewards, or diagnosing a level that plays as boring, confusing, or where players get lost or stuck. Engine-agnostic craft: the blockout->greybox->playtest->art pipeline, sightlines and landmarks, tension/release rhythm, the introduce->develop->twist->combine encounter progression, readability via light/color/composition, and traversal heatmaps. Triggers: 'design this level', 'my level is boring/confusing', 'players keep getting lost', 'how do I pace this', 'blockout', 'greybox', 'encounter design', 'where do I put the secret'. NOT systemic mechanics or economy tuning (that's game-design), NOT narrative or story beats (that's game-storytelling), and NOT engine-specific level tooling — nav meshes, occlusion, tilemap editors, lightmap baking (that's the godot/unity/unreal skill).",
2573
+ "description": "Use when designing a game level's space — blockout/greybox layout, pacing that drags or spikes, guiding lost players without waypoints, encounter and arena progression, or secret placement. NOT mechanics or economy (that is `game-design`), NOT story beats (that is `game-storytelling`), NOT engine tooling like nav meshes or lightmaps (that is `godot`/`unity`/`unreal`).",
2574
2574
  "tags": [
2575
2575
  "level-design",
2576
2576
  "blockout",
@@ -4466,7 +4466,7 @@
4466
4466
  },
4467
4467
  {
4468
4468
  "id": "spring-boot",
4469
- "description": "Use when building, reviewing, testing, securing, or configuring a Spring Boot 4 / Spring Framework 7 backend — controllers, services, Spring Data JPA, application.yml, SecurityFilterChain, slice tests. Triggers: 'add a REST endpoint', 'wire up @Service and @Repository', 'my @Transactional isn't rolling back', 'LazyInitializationException after the session closed', 'N+1 select on a lazy collection', '@WebMvcTest + mock the service', 'migrate WebSecurityConfigurerAdapter', 'monta la seguridad con SecurityFilterChain', 'per què surt LazyInitializationException', a file importing org.springframework.boot.*, a pom.xml with spring-boot-starter-web, or an application.yml. NOT plain modern-Java language work like records/streams/virtual threads (that is java); NOT engine-level SQL schema/index/EXPLAIN (that is postgresdb); NOT container/CI mechanics (that is deployment).",
4469
+ "description": "Use when building, reviewing, testing, securing or configuring a Spring Boot 4 / Framework 7 backend — controllers, services, Spring Data JPA, application.yml, SecurityFilterChain, slice tests. NOT plain modern-Java language work like records or virtual threads (that is `java`); NOT engine-level SQL schema/index/EXPLAIN (that is `postgresdb`).",
4470
4470
  "tags": [
4471
4471
  "java",
4472
4472
  "spring",
@@ -4823,7 +4823,7 @@
4823
4823
  },
4824
4824
  {
4825
4825
  "id": "together-fireworks",
4826
- "description": "Use when calling hosted open-model inference on Together AI or Fireworks AI — pointing the OpenAI SDK at api.together.ai or api.fireworks.ai, picking an open model (Llama, DeepSeek, Qwen, GPT-OSS) and what it costs, or cutting the bill with batch inference. Triggers: 'call DeepSeek/Llama on Together', 'wire the OpenAI SDK to Fireworks', 'why is my model name 404ing', 'which open-source model and how much per million tokens', 'halve my LLM bill with batch', 'move off GPT-4 to a cheaper open-weights endpoint', 'serverless vs dedicated for sustained QPS', '¿qué modelo open source uso y cuánto cuesta?', 'abaratar la factura de inferència'. NOT renting raw GPUs to self-host weights (that is runpod), NOT running a model locally with zero marginal cost (that is ollama).",
4826
+ "description": "Use when calling open-weight LLMs on Together AI or Fireworks AI's OpenAI-compatible endpoints — `base_url` plus namespaced model id, the cheapest model that clears the bar, per-1M-token cost math, serverless vs batch vs dedicated. NOT renting GPUs to self-host weights (that is `runpod`), NOT running a model locally for free (that is `ollama`).",
4827
4827
  "tags": [
4828
4828
  "llm",
4829
4829
  "inference",
@@ -5240,7 +5240,7 @@
5240
5240
  },
5241
5241
  {
5242
5242
  "id": "youtube-api",
5243
- "description": "Use when connecting a real YouTube channel to code via the Data API v3 (uploads, metadata) and Analytics API v2 (performance) — OAuth, resumable video upload, editing title/description/tags/privacy after publish, pulling views/watch time/averageViewPercentage/retention/traffic sources — and logging that performance into 02-DOCS/wiki/youtube/ as a dated feedback log. Triggers: 'upload a video to my channel via the API and set its tags', 'videos.insert returns 403 quotaExceeded / uploadLimitExceeded', 'my YouTube refresh token keeps dying after about 7 days', 'pull the audienceWatchRatio retention curve for video X', 'fetch this month's traffic sources and write them into the wiki', 'subir vídeos a YouTube por API y guardar las estadísticas del canal', 'treure les estadístiques del canal i guardar-les al wiki'. NOT what-to-publish or how-to-package it (that is youtube-strategy / youtube-packaging).",
5243
+ "description": "Use when wiring code to a real YouTube channel: user OAuth 2.0, resumable videos.insert uploads, editing metadata after publish, pulling views/watch time/retention/traffic from the Analytics API v2 into a dated 02-DOCS/wiki/youtube/ feedback log. NOT what to publish or how to title and thumbnail it (that is youtube-strategy / youtube-packaging).",
5244
5244
  "tags": [
5245
5245
  "youtube",
5246
5246
  "youtube-data-api",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ericrisco/rsc",
3
- "version": "0.1.57",
3
+ "version": "0.1.59",
4
4
  "description": "Eric Risco's agent-skills catalog as a granular, self-recommending CLI installer.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gamedev-physics
3
- description: "Use when working with a game engine's physics — rigid bodies, colliders, collision layers/masks, character controllers, joints, forces vs impulses, raycasts/shapecasts, or when physics is unstable. Triggers: \"my character falls through the floor\", \"bullet tunnels through walls at high speed\", \"rigidbody jitters / vibrates / explodes\", \"objects that should collide pass through each other\", \"which collision layer and mask do I set\", \"kinematic vs dynamic body\", \"move_and_slide / CharacterBody\", \"AddForce vs impulse vs setting velocity\", \"physics in FixedUpdate or _physics_process\", \"slope and step detection\", \"trigger / Area overlap not firing\", Godot RigidBody/StaticBody/CharacterBody/Area, Unity Rigidbody/Collider/CharacterController, Unreal Chaos/collision presets. NOT rendering, materials, or visual jitter from shaders (use gamedev-shaders); NOT AI navigation, pathfinding, or navmesh (use gamedev-pathing)."
3
+ description: "Use when working with a game engine's physics — rigid bodies, colliders, collision layers and masks, character controllers, joints, forces versus impulses, raycasts and shapecasts, or when a simulation is unstable (tunnelling, jitter, missed overlaps). Covers the Godot, Unity and Unreal equivalents. NOT rendering or shader-driven visual jitter (that is `gamedev-shaders`), NOT navigation, pathfinding or navmesh (that is `gamedev-pathing`)."
4
4
  tags: [physics, collision, rigidbody, character-controller, colliders]
5
5
  recommends: [godot, unity, unreal, gamedev-pathing]
6
6
  profiles: [full]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: git-workflow
3
- description: "Use when naming or scoping a branch, writing or fixing a commit message, untangling history (rebase vs merge vs squash), or cutting a versioned release — the portable git-convention layer that works on any repo. Triggers: 'name this branch', 'is this commit message conventional?', 'rebase or merge before the PR?', 'squash these wip commits into one', 'my git log is a mess', 'tag a release', 'write release notes', 'what version should this release be?', 'clean up history before review', 'limpia el historial antes del PR', '¿qué versión le toca a esta release?', 'deja los commits en formato convencional'. Covers Conventional Commits 1.0.0, SemVer tags, branch hygiene, force-push safety, and gh pr/release mechanics. NOT the I'm-done land-it decision and pre-ship checklist (that is ship), NOT setting up an isolated checkout before coding (that is worktrees), NOT CI/CD release automation in GitHub Actions (that is deployment)."
3
+ description: "Use when naming or scoping a branch, writing or fixing a commit message, untangling history (rebase versus merge versus squash), or cutting a versioned release — the portable git-convention layer for any repo. Covers Conventional Commits, SemVer tags, branch hygiene, force-push safety and gh pr/release mechanics. NOT the land-it decision and pre-ship checklist (that is `ship`), NOT an isolated checkout before coding (that is `worktrees`), NOT CI/CD release automation (that is `deployment`)."
4
4
  tags: [git, version-control, conventional-commits, semver, pull-request]
5
5
  recommends: [ship, worktrees, deployment, github-actions]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: google-workspace
3
- description: "Use when building server-side automation that reads or writes Gmail, Drive, Calendar, or Sheets against a real Google Workspace account via the official client libraries and a GCP service account — picking the auth mode, scoping OAuth scopes, building the authed client, and debugging 403/429/unauthorized_client errors. Triggers: 'send mail from a service account in a cron', 'unauthorized_client when impersonating a user', 'which Drive scope to upload to a shared drive', 'set up domain-wide delegation client ID', 'getting 403 insufficient permissions from the Sheets API', 'automatizar Gmail con cuenta de servicio sin login del usuario', 'enviar correos desde un script sense login d'usuari'. NOT generic SMTP/marketing/deliverability email (that is email-connector)."
3
+ description: "Use when server-side code reads or writes Gmail, Drive, Calendar, or Sheets with a GCP service account and no human in the OAuth loop: picking the auth mode (app-owned vs domain-wide delegation vs keyless), scoping to least privilege, building the authed Node/Python client, staying under per-user quota, and debugging unauthorized_client / 403 / 429. NOT SMTP providers or deliverability (that is `email-connector`), NOT slot-finding and booking UX (that is `calendar-scheduling`)."
4
4
  tags: [google-workspace, gmail-api, drive-api, calendar-api, sheets-api, service-account, domain-wide-delegation, oauth-scopes]
5
5
  recommends: [email-connector, calendar-scheduling, spreadsheet-ops, document-processing, automation-flows, secure-coding, webhooks]
6
6
  origin: risco
@@ -9,52 +9,22 @@ origin: risco
9
9
  # Google Workspace — auth + calling Gmail/Drive/Calendar/Sheets
10
10
 
11
11
  This skill owns one layer: **authenticating to and calling the four Google
12
- Workspace REST APIs from server-side code.** You pick the auth mode, scope the
13
- OAuth scopes to least privilege, build the authed client in Node or Python, and
14
- call Gmail / Drive / Calendar / Sheets with quota-safe patterns. It turns "I
15
- have a GCP project and a Workspace domain" into code that sends mail, moves
16
- files, books events, and reads/writes spreadsheets without a human in the OAuth
17
- loop.
18
-
19
- It does NOT own email-as-a-product, scheduling-as-a-product, or
20
- spreadsheet-as-data. See the boundaries below before you start.
21
-
22
- Operating posture:
23
-
24
- - **No human in the loop.** Everything here is service-account / machine auth.
25
- If a real user must click "Allow", that is interactive OAuth — out of scope.
26
- - **Least scope, keyless first.** Default to the narrowest scope and to
27
- Application Default Credentials / Workload Identity Federation over a
28
- downloaded JSON key. A leaked key is the single most common Workspace
29
- credential compromise.
30
- - **Quota is a real constraint, not a footnote.** The per-user limits are tight
31
- (6k units/min Gmail, 60 req/min Sheets). Build backoff in from line one.
32
-
33
- ## When to use / When NOT to use
34
-
35
- **Use when:** a cron, webhook handler, or agent tool reads/writes Gmail, Drive,
36
- Calendar, or Sheets without an interactive login; you must decide between
37
- app-owned resources and impersonating each Workspace user; you hit
38
- `403 insufficient permissions`, `403 rateLimitExceeded`, `429`, or
39
- `unauthorized_client` and need the scope/delegation/quota fix; you are wiring
40
- `googleapis` (Node) or `google-api-python-client` + `google-auth` (Python);
41
- you are migrating off downloaded JSON keys toward keyless auth.
42
-
43
- **Do NOT use for:**
44
-
45
- - **Generic transactional/marketing email, SMTP, providers, deliverability,
46
- SPF/DKIM** → `email-connector` and `email-deliverability`. This skill covers
47
- Gmail-the-API inside a Workspace mailbox, not provider choice or inbox
48
- placement.
49
- - **Scheduling logic, availability, booking-link UX, timezone-as-a-feature** →
50
- `calendar-scheduling`. This skill covers the raw Calendar event CRUD it sits
51
- on top of.
52
- - **Spreadsheet data modeling, formulas, pivots, transforms as the deliverable**
53
- → `spreadsheet-ops`. This skill covers the Sheets API read/write transport.
54
- - **Doc/PDF parsing, extraction, OCR** → `document-processing`. Drive here is
55
- storage transport (upload/download/move/permissions), not content extraction.
56
- - **Multi-step orchestration across connectors** → `automation-flows`. **Notion**
57
- → `notion-connector`. **Generic REST wrapping** → `api-connector-builder`.
12
+ Workspace REST APIs from server-side code.** Everything here is service-account
13
+ / machine auth — if a real user must click "Allow", that is interactive OAuth and
14
+ out of scope.
15
+
16
+ Where the neighbouring layers live:
17
+
18
+ | Not this skill | Goes to | This skill's slice |
19
+ |---|---|---|
20
+ | SMTP/provider choice, transactional/marketing sends | `email-connector` | Gmail-the-API inside a Workspace mailbox |
21
+ | SPF/DKIM, inbox placement | `email-deliverability` | — |
22
+ | Availability search, booking-link UX, timezone-as-a-feature | `calendar-scheduling` | Raw Calendar event CRUD underneath |
23
+ | Sheet data modeling, formulas, pivots | `spreadsheet-ops` | Sheets API read/write transport |
24
+ | Doc/PDF parsing, extraction, OCR | `document-processing` | Drive as storage transport (upload/download/move/permissions) |
25
+ | Chaining several connectors into one flow | `automation-flows` | The individual Google calls |
26
+ | Notion as the backend / generic REST wrapping | `notion-connector`, `api-connector-builder` | — |
27
+ | Receiving Gmail/Drive push notifications | `webhooks` | — |
58
28
 
59
29
  ## Pick your auth mode
60
30
 
@@ -72,7 +42,9 @@ large blast radius. Use it only when you genuinely must act as the user.
72
42
 
73
43
  ## Setup checklist
74
44
 
75
- Do these in order. The full click-path is in `references/auth-setup.md`.
45
+ Do these in order. `references/auth-setup.md` has the full Cloud + Admin
46
+ click-path, the scope catalog, DWD authorization, keyless WIF/ADC, and a longer
47
+ troubleshooting matrix.
76
48
 
77
49
  1. **Enable the APIs** you will call in the Cloud console (Gmail, Drive,
78
50
  Calendar, Sheets) for the project. A disabled API returns `403` regardless of
@@ -242,8 +214,9 @@ def with_backoff(call, max_retries=6, max_backoff=64):
242
214
  - **Never commit the SA key JSON.** It is a long-lived bearer credential — a
243
215
  committed `service_account.json` is game over. Add `*.json` SA patterns to
244
216
  `.gitignore`; the `verify.sh` here flags tracked keys.
245
- - **Prefer keyless.** On GCP/CI use ADC or Workload Identity Federation so there
246
- is no file to leak. If you must use a key, store it in a secret manager
217
+ - **Prefer keyless.** A leaked key is the single most common Workspace credential
218
+ compromise. On GCP/CI use ADC or Workload Identity Federation so there is no
219
+ file to leak. If you must use a key, store it in a secret manager
247
220
  (env-injected, not a file beside the code) and rotate it.
248
221
  - **Least scope.** A leaked `drive.file` key sees app files; a leaked full
249
222
  `drive` key sees everything. The scope IS the blast radius.
@@ -268,20 +241,6 @@ def with_backoff(call, max_retries=6, max_backoff=64):
268
241
  | Reading whole resources without `fields` | Bigger payloads, higher quota cost, slower | Request only the fields you use (`fields: 'id'`) |
269
242
  | Hardcoding the private key inline in source | Can't rotate, leaks via logs/screenshots/history | Inject from env/secret manager; `\n`-unescape at load |
270
243
  | Pasting raw text into Gmail `raw` | API needs base64url RFC 822, not plain text → 400 | Build a MIME message, `base64url`-encode it |
271
- | Setting `subject` but skipping the Admin DWD step | `unauthorized_client` — the SA was never allowed to impersonate | Authorize client ID + exact scopes in Manage DWD first |
272
-
273
- ## See also
274
-
275
- - `../secure-coding/SKILL.md` — secret handling, key rotation, and the security
276
- pass before this connector ships.
277
-
278
- Recommended companions (siblings; create/link when present): `email-connector`
279
- for SMTP/provider/deliverability email, `calendar-scheduling` for slot-finding
280
- and booking UX, `spreadsheet-ops` for sheet data modeling and formulas,
281
- `document-processing` for parsing files you pull from Drive, `automation-flows`
282
- for chaining this across multiple connectors, and `webhooks` for receiving
283
- Gmail/Drive push notifications.
284
244
 
285
- Deep dives: `references/auth-setup.md` (full Cloud + Admin walkthrough, scope
286
- catalog, DWD authorization, keyless WIF/ADC, troubleshooting matrix) and
287
- `references/api-recipes.md` (extended Node + Python recipes).
245
+ Before this connector ships, run the secret-handling and key-rotation pass in
246
+ `../secure-coding/SKILL.md`.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: htmx
3
- description: "Use when adding interactivity to a server-rendered app (FastAPI/Jinja, Django, Rails, Laravel, Go templates, Express) without adopting a JS framework, wiring hx-get/post/put/delete plus hx-target plus hx-swap plus hx-trigger, returning HTML fragments instead of JSON, doing out-of-band swaps, or building active search, infinite scroll, inline edit, click-to-load, and polling. Triggers: 'swap a server partial into a div on click', 'return an HTML fragment not JSON', 'render a fragment on HX-Request else the full page', 'update the cart count and drawer from one response', 'live search box without React', 'afegir interactivitat a la meva app Django sense muntar un SPA', 'intercambiar un fragmento HTML del servidor', 'buscador en vivo sin SPA'. NOT a client-state SPA with routing/store (that is react / nextjs)."
3
+ description: "Use when adding interactivity to a server-rendered app (FastAPI/Jinja, Django, Rails, Laravel, Go templates, Express) without adopting a JS framework — hx-get/post/put/delete with hx-target, hx-swap and hx-trigger, returning HTML fragments instead of JSON, out-of-band swaps, active search, infinite scroll, inline edit and polling. NOT a client-state SPA with routing and a store (that is `react` or `nextjs`)."
4
4
  tags: [htmx, hypermedia, frontend, server-rendered, html]
5
5
  recommends: [fastapi, django, secure-coding, accessibility]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: huggingface
3
- description: "Use when running open models or working on the Hugging Face platform: calling a model via the Inference Providers router or InferenceClient, downloading/uploading/versioning repos on the Hub with the hf CLI, deploying a dedicated Inference Endpoint with scale-to-zero, hosting a Gradio Space with ZeroGPU, picking an open model by task/license/size, or loading a model locally with transformers. Triggers: 'call an open model through Hugging Face', 'InferenceClient embeddings', 'hf download/upload', 'write a model card', 'router.huggingface.co', 'my hf-inference serverless call 404s on a 70B model', 'scale-to-zero endpoint', 'ZeroGPU Space', 'desplegar un modelo de Hugging Face con escalado a cero'. NOT serving a model locally on your own machine (that is ollama), NOT renting and operating your own GPU box (that is runpod), NOT generating creative images via a hosted API (that is replicate-images), NOT fine-tuning with trl/peft (that is finetuning), NOT building training datasets (that is training-data)."
3
+ description: "Use when running open models or working on the Hugging Face platform — the Inference Providers router or InferenceClient, Hub repos via the hf CLI, a dedicated Inference Endpoint with scale-to-zero, a Gradio Space with ZeroGPU, picking an open model by task/license/size, or loading one locally with transformers. NOT serving locally on your own machine (that is `ollama`), NOT renting your own GPU box (that is `runpod`), NOT hosted creative image APIs (that is `replicate-images`), NOT fine-tuning with trl/peft (that is `finetuning`)."
4
4
  tags: [huggingface, inference-providers, transformers, model-hub, inference-endpoints, spaces, ai-infra]
5
5
  recommends: [ollama, runpod, modal, replicate, together-fireworks, fal, rag, embeddings-search, prompt-engineering, llm-pipeline, ai-media]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: inventory
3
- description: "Use when deciding how much stock to hold and when to reorder it — classifying SKUs, sizing safety stock, setting reorder points and order quantities, and tracking inventory KPIs so a business neither stocks out nor sits on dead stock. Triggers: 'what should my reorder point be', 'how much safety stock', 'run an ABC analysis', 'set up min/max levels', 'should I review weekly or continuously', 'we keep running out of X while sitting on a year of Y', 'too much cash tied up in stock', 'punt de comanda', 'stock de seguretat', 'cuánto stock de seguridad necesito si el proveedor a veces tarda el doble'. NOT raising or negotiating the purchase order itself (that is procurement)."
3
+ description: "Use when deciding how much stock to hold and when to reorder it — classifying SKUs, sizing safety stock, setting reorder points and order quantities, and tracking the KPIs that keep a business from either stocking out or sitting on dead stock. NOT raising or negotiating the purchase order itself (that is `procurement`)."
4
4
  tags: [reorder-point, safety-stock, eoq, abc-xyz, replenishment, inventory-kpis, ddmrp, min-max]
5
5
  recommends: [procurement, logistics-ops, forecasting, dashboard, reporting, spreadsheet-ops]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: investor-materials
3
- description: "Use when packaging, organizing, or circulating the documents an investor reads OUTSIDE the meeting — setting up or cleaning a data room, writing the investor one-pager/teaser that earns the first meeting, or drafting the recurring monthly/quarterly investor update — symptoms include unnamed dump-folder files, no follow-on warmth, or needing the attachment a cold email carries. Triggers: 'set up our data room', 'what docs do investors expect before diligence', 'write our investor one-pager / teaser', 'draft this month's investor update', 'our data room is a mess, rename and reorganize the files', 'set up a reusable monthly update format', 'sala de datos para inversores', 'actualización mensual a inversores', 'sala de dades / resum d'una pàgina per a inversors'. NOT the slide narrative (that is pitch-deck), NOT the projection spreadsheet (that is financial-model), NOT the round strategy and investor pipeline (that is fundraising)."
3
+ description: "Use when packaging or circulating the documents an investor reads outside the meeting — setting up or cleaning a data room, writing the one-pager or teaser that earns the first meeting, or drafting the recurring monthly investor update. NOT the slide narrative (that is `pitch-deck`), NOT the projection spreadsheet (that is `financial-model`), NOT round strategy and the investor pipeline (that is `fundraising`)."
4
4
  tags: [fundraising, data-room, investor-update, one-pager, investor-relations, due-diligence]
5
5
  recommends: [pitch-deck, financial-model, fundraising, cold-outreach, unit-economics, grants]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ip-trademark
3
- description: "Use when a non-lawyer operator needs to protect a brand or creative work — clearing and choosing a name/logo, deciding whether and where to register a trademark, using ™/® correctly, knowing what copyright they get for free, or checking whether they actually own work they paid a freelancer for. Triggers: 'can I use this name', 'is this trademark taken', 'when can I put the ® on our logo', 'we paid the freelancer so we own it, right?', 'is our AI-generated logo copyrightable', 'register the trademark in the US or the EU', 'someone copied our content, what can we do', '¿puedo registrar esta marca?', '¿de quién es el copyright del logo?'. NOT drafting the IP-assignment clause itself (that is contracts)."
3
+ description: "Use when a non-lawyer operator needs to protect a brand or creative work — clearing and choosing a name or logo, deciding whether and where to register a trademark, using the trademark and registered symbols correctly, knowing what copyright is automatic, or checking whether they own work a freelancer was paid for. NOT drafting the IP-assignment clause itself (that is `contracts`)."
4
4
  tags: [intellectual-property, trademark, copyright, licensing, legal-compliance]
5
5
  recommends: [contracts, brand-identity, compliance, terms-conditions]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: java
3
- description: "Use when writing, reviewing, or refactoring modern Java (21+, Java 25 LTS) - records and sealed interfaces as algebraic data types, exhaustive pattern-matching switch over instanceof+cast ladders, virtual-thread (Project Loom) concurrency one-task-per-thread, structured concurrency and ScopedValue replacing ThreadLocal, Stream/Optional/Collector pipelines, compact-constructor validation, parametrized JDBC, and the Maven 3.9 / Gradle 9 build surface against a current JDK. Triggers: \"write a Java service\", \"is this idiomatic Java\", \"refactor this instanceof ladder\", \"fetch 500 URLs concurrently\", \"model this domain with records\", .java files, pom.xml, build.gradle, the non-obvious \"my ThreadLocal context disappears inside the tasks I submit\" (that is ScopedValue), \"modela este dominio de pagos con tipos inmutables\", \"refactoritza aquest switch\". NOT Spring framework wiring (that is spring-boot)."
3
+ description: "Use when writing, reviewing or refactoring modern Java (21+, 25 LTS) — records and sealed interfaces as algebraic data types, exhaustive pattern-matching switch over instanceof ladders, virtual-thread concurrency, structured concurrency and ScopedValue replacing ThreadLocal, Stream and Optional pipelines, compact-constructor validation, parametrized JDBC, and the Maven/Gradle build surface. NOT Spring framework wiring (that is `spring-boot`)."
4
4
  tags: [java, jvm, records, virtual-threads, sealed-types]
5
5
  recommends: [spring-boot, secure-coding, deployment]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: kotlin-android
3
- description: "Use when building or fixing a native Android app in Kotlin + Jetpack Compose with the UDF layered architecture (ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe Navigation, Gradle/AGP setup). Triggers: a Compose screen that recomposes every frame or loses state on rotation, wiring ViewModel state into the UI, an offline-first repository, a Hilt DI graph, a Room DAO, build.gradle.kts/version-catalog and AGP/Kotlin floors, 'cómo expongo el estado del ViewModel con StateFlow', 'la pantalla Compose se recompone en cada frame', 'mi app Android pierde el estado al rotar'. NOT shared Android+iOS UI from one Kotlin codebase (that is compose-multiplatform)."
3
+ description: "Use when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe Navigation, and the Gradle/AGP surface. NOT shared Android and iOS UI from one Kotlin codebase (that is `compose-multiplatform`)."
4
4
  tags: [kotlin, android, jetpack-compose, hilt, room, coroutines, mvvm, clean-architecture]
5
5
  recommends: [compose-multiplatform, spring-boot, java, testing-web, github-actions]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: kpi-framework
3
- description: "Use when a team must decide what to measure before building anything — picking one north-star metric, separating leading input drivers from lagging outputs, adding guardrails so a number can't be gamed, or setting a target that isn't arbitrary. Triggers: 'what should we even be measuring', 'we track 40 KPIs and nothing leads anywhere', 'is signups a leading or lagging indicator', 'set an activation target that won't get gamed', 'pick a north star for the product', 'audit our vanity metrics', 'quins KPIs triem per al producte', 'qué métrica norte elegimos'. NOT building the live dashboard that displays them (that is dashboard), NOT instrumenting the events (that is analytics), NOT the recurring board report (that is reporting)."
3
+ description: "Use when a team must decide what to measure before building anything — picking one north-star metric, separating leading input drivers from lagging outputs, adding guardrails so a number cannot be gamed, and setting a target that is not arbitrary. NOT the live dashboard that displays them (that is `dashboard`), NOT instrumenting the events (that is `analytics`), NOT the recurring board report (that is `reporting`)."
4
4
  tags: [north-star-metric, leading-vs-lagging, input-metrics, guardrail-metrics, target-setting, vanity-metrics, kpi-tree]
5
5
  recommends: [analytics, dashboard, reporting, ab-testing, forecasting, business-intelligence, unit-economics, project-ops]
6
6
  origin: risco
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: level-design
3
- description: "Use when designing a game level, map, arena, or encounter — laying out a blockout/greybox, fixing pacing that drags or spikes, guiding players without hand-holding, placing secrets and rewards, or diagnosing a level that plays as boring, confusing, or where players get lost or stuck. Engine-agnostic craft: the blockout->greybox->playtest->art pipeline, sightlines and landmarks, tension/release rhythm, the introduce->develop->twist->combine encounter progression, readability via light/color/composition, and traversal heatmaps. Triggers: 'design this level', 'my level is boring/confusing', 'players keep getting lost', 'how do I pace this', 'blockout', 'greybox', 'encounter design', 'where do I put the secret'. NOT systemic mechanics or economy tuning (that's game-design), NOT narrative or story beats (that's game-storytelling), and NOT engine-specific level tooling — nav meshes, occlusion, tilemap editors, lightmap baking (that's the godot/unity/unreal skill)."
3
+ description: "Use when designing a game level's space — blockout/greybox layout, pacing that drags or spikes, guiding lost players without waypoints, encounter and arena progression, or secret placement. NOT mechanics or economy (that is `game-design`), NOT story beats (that is `game-storytelling`), NOT engine tooling like nav meshes or lightmaps (that is `godot`/`unity`/`unreal`)."
4
4
  tags: [level-design, blockout, pacing, encounter, playtest]
5
5
  recommends: [game-design, godot, unity, unreal]
6
6
  profiles: [full]
@@ -11,29 +11,12 @@ origin: risco
11
11
 
12
12
  *Shape the space, the rhythm, and the encounters so the player always knows where to go, never gets bored, and feels smart for exploring. Prove it in grey boxes; add art last.*
13
13
 
14
- This skill owns the **craft of physical space and its play**: how a level is laid out, how it reads, how its intensity rises and falls, how encounters teach, and where reward hides. It is **engine-agnostic** — every technique here is validated in a blockout, then handed to an engine skill for the actual tooling (nav meshes, occlusion, lightmaps, tilemaps). It does not design the mechanics the level exercises (that's the systemic layer) or write the story it tells.
15
-
16
- ## When to use / When NOT to use
17
-
18
- **Use when:** blocking out a new level/map/arena; a level playtests as boring, confusing, or too hard/easy; players get lost or stuck; you need to pace a level, space encounters, or add breathers; you're guiding players without arrows/waypoints; placing secrets, rewards, or shortcuts; teaching a mechanic through the space itself.
19
-
20
- **Do NOT use for:**
21
-
22
- - **Systemic / mechanic design** — the verbs, rules, economy, and numbers the player brings *into* the level (jump height as a rule, weapon balance, loot tables, progression systems). That's `game-design`. This skill *exercises* those verbs in space; it doesn't invent or tune them.
23
- - **Narrative, quests, dialogue, environmental story beats** — what the space *says*. That's `game-storytelling`. Level design places the beat; storytelling writes it.
24
- - **Engine-specific level tooling** — nav-mesh baking, occlusion culling, terrain/tilemap/ProBuilder editors, lightmap/GI bakes, streaming volumes, collision setup. Defer to `godot` / `unity` / `unreal`. This skill decides *what* the space must do; the engine skill implements *how*.
25
-
26
- ## The craft laws (non-negotiable)
27
-
28
- 1. **Art last.** Never model or texture a space you haven't proven fun in blockout. Art-first means reworking expensive assets when the layout inevitably changes.
29
- 2. **Metrics before geometry.** Lock the player's dimensions (height, jump, reach, cover) first; build everything as multiples of them. → `references/blockout-to-art.md`
30
- 3. **The player always knows where to go, never how it ends.** Guide the critical path; leave exploration to earn its own reward. Lostness is a readability bug, not player error.
31
- 4. **Watch, don't tell.** A level is only as good as it plays for someone you didn't coach. Every claim ("this is obvious", "the fight is fun") is a hypothesis until a fresh player validates it.
32
- 5. **Rhythm, not a flat line.** Intensity must rise and fall. Sustained peak = fatigue; sustained calm = boredom. Design the graph, not just the rooms.
33
- 6. **Teach through space, not text.** Introduce a threat where it's safe to learn it, before it can kill.
14
+ This skill owns the **craft of physical space and its play**: how a level is laid out, how it reads, how its intensity rises and falls, how encounters teach, and where reward hides. It is **engine-agnostic** — every technique here is validated in a blockout, then handed to an engine skill for the actual tooling.
34
15
 
35
16
  ## The pipeline: blockout -> greybox -> playtest -> art (never art-first)
36
17
 
18
+ **Lock the player's metrics first** — height, jump, reach, cover, door/corridor widths — and build all geometry as multiples of them. Guessing widths breaks traversal after the space is full of dependent geometry, which is why this comes before the first box. → `references/blockout-to-art.md`
19
+
37
20
  | Stage | You build | You answer | Gate to next |
38
21
  |---|---|---|---|
39
22
  | **Blockout** | Primitive geometry only (boxes/planes at true metrics). No materials, no props. | Does the space flow? Are timings/distances right? Can I find my way? | Layout & traversal feel right. |
@@ -41,7 +24,7 @@ This skill owns the **craft of physical space and its play**: how a level is lai
41
24
  | **Playtest** | Nothing — you watch fresh players. | Where do they hesitate, get lost, die, skip? | Fixes are cheap because it's still grey. |
42
25
  | **Art pass** | Meshes, materials, VFX, final lighting, audio — *serving* the proven layout. | Does art reinforce the guidance the greybox already established? | Ship. |
43
26
 
44
- Iterate blockout↔playtest many times before art. Changing a grey box is minutes; changing a finished art set-piece is days. Full stage detail, the metrics block, and the art-pass handoff checklist → `references/blockout-to-art.md`.
27
+ Iterate blockout↔playtest many times before art: changing a grey box is minutes, changing a finished art set-piece is days — so never model or texture a space you have not already proven fun. Full stage detail, the metrics block, and the art-pass handoff checklist → `references/blockout-to-art.md`.
45
28
 
46
29
  ## Spatial composition — leading the eye
47
30
 
@@ -49,13 +32,13 @@ Iterate blockout↔playtest many times before art. Changing a grey box is minute
49
32
  - **Landmarks (the "weenie").** One large, distinct, distant silhouette per area that the player orients toward (tower, spire, mountain) — Disney's term for the visual magnet that pulls you forward. Self-locating beats a minimap.
50
33
  - **Lead the eye** with converging lines (rails, beams), framing (foreground arches), contrast (a bright end to a dark corridor), and motion. The eye goes to the brightest, highest-contrast, most-different thing — put that on the path you want taken.
51
34
  - **Silhouette readability.** Enemies, interactables, and hazards must read by shape alone at a glance. Two things sharing a silhouette is an unintended trap.
52
- - **Golden path vs exploration.** The **critical path** is the always-legible guaranteed route to the objective; **exploration** is optional branches and loops off it. Prefer loops that return the player forward (avoid dead-end backtracking); breadcrumb side routes with a visible reward.
35
+ - **Golden path vs exploration.** The **critical path** is the always-legible guaranteed route to the objective; **exploration** is optional branches and loops off it. The player must always know where to go and never how it ends. Prefer loops that return the player forward (avoid dead-end backtracking); breadcrumb side routes with a visible reward.
53
36
 
54
37
  Framing, contrast, and layout topologies (loops, hubs, gates) → `references/guidance-and-readability.md`.
55
38
 
56
39
  ## Pacing & rhythm — tension and release
57
40
 
58
- Design the **intensity graph** for the whole level, not room by room. A good level is a sawtooth trending upward: each peak (combat, platforming gauntlet, chase) followed by a valley — a **safe room / breather** with no threat, low stimulus, often a save/restock.
41
+ Design the **intensity graph** for the whole level, not room by room. Intensity must rise and fall — sustained peak is fatigue, sustained calm is boredom. A good level is a sawtooth trending upward: each peak (combat, platforming gauntlet, chase) followed by a valley — a **safe room / breather** with no threat, low stimulus, often a save/restock.
59
42
 
60
43
  - **Space encounters in time and distance, and *vary* both** — three identical-length fights back to back feel like one long slog.
61
44
  - **Breathers earn the next peak.** The calm between (Halo's cadence is often described as "thirty seconds of fun" on repeat) is what makes the fun read as fun. Use it to let adrenaline drop, reward observation, and telegraph the next escalation.
@@ -66,7 +49,7 @@ Intensity-graph template, breather patterns, and difficulty-curve worked example
66
49
 
67
50
  ## Encounter design — introduce, develop, twist, combine
68
51
 
69
- The four-beat progression teaches a mechanic/threat through space (the pattern behind Portal, Half-Life 2, and Mario level craft):
52
+ Teach through space, not text: the four-beat progression (the pattern behind Portal, Half-Life 2, and Mario level craft) introduces a threat where it is safe to learn, before it can kill.
70
53
 
71
54
  1. **Introduce** — meet the new element somewhere it *can't* hurt you. A single turret across a safe gap; one platform of the new hazard. Learn it risk-free.
72
55
  2. **Develop** — use it for real, low stakes. The turret now guards a corridor you must cross.
@@ -84,7 +67,7 @@ Encounter template, arena patterns, and a full introduce→develop→twist→com
84
67
 
85
68
  ## Guidance & readability — direct without hand-holding
86
69
 
87
- Guide with the environment so you never need a floating arrow:
70
+ Guide with the environment so you never need a floating arrow. When a player is lost, that is a readability bug in the level, not player error:
88
71
 
89
72
  - **Light leads.** Players move toward light (the moth effect) and higher value-contrast. Light the path, objective, and exit; keep dead-ends dim. Placeholder lighting is a greybox *design* tool, not a final-art afterthought.
90
73
  - **Reserve one accent color for "you can interact / go here"** (Mirror's Edge runner red, Dishonored's usable glint) and **never** use it decoratively. Consistency is the whole point; break it once and you've lied to the player.
@@ -96,7 +79,7 @@ Full catalog — lighting/color/composition, the affordance language, the "criti
96
79
 
97
80
  ## Metrics & playtesting — where players get lost and stuck
98
81
 
99
- You cannot see your own level fresh. **Observe, don't coach:**
82
+ You cannot see your own level fresh, so every claim ("this is obvious", "the fight is fun") is a hypothesis until a fresh player validates it. **Observe, don't coach:**
100
83
 
101
84
  - **Watch a first-timer play, silent.** Note every hesitation (readability gap), wrong turn (navigation gap), repeated death (telegraph/difficulty gap), and skipped content (reward-placement gap). Do **not** answer "where do I go?" — that question *is* the finding.
102
85
  - **Traversal telemetry** turns anecdote into pattern: **position heatmaps** (cold zones players never enter = wasted level), **death heatmaps** (clusters = unfair/unreadable threats), **path traces** (golden path or lost?), **dwell time** at forks (long dwell = unclear guidance), and **look/aim heatmaps** (did they even see the landmark?).
@@ -114,41 +97,26 @@ Playtest protocol, question scripts, and turning heatmaps into fixes → `refere
114
97
 
115
98
  Reward taxonomy, secret-signposting, and risk/reward tuning → `references/guidance-and-readability.md`.
116
99
 
117
- ## Anti-patterns / rationalizations -> STOP
100
+ ## Anti-patterns
118
101
 
119
- | Rationalization | Reality / Fix |
102
+ | Anti-pattern | Do instead |
120
103
  |---|---|
121
- | "Let's make it look good first, then tune the layout." | Art-first burns days reworking assets when the layout changes. Blockout, playtest, *then* art. |
122
- | "It's obvious where to go." | Obvious to *you*, the author. Fresh players get lost. Watch one before you believe it. |
123
- | "I'll just add a waypoint arrow / big text prompt." | That's a patch over a readability failure. Fix it with light, framing, and a landmark first. |
124
- | "The whole level is intense — it's exciting!" | Sustained peak = fatigue and it all flattens into noise. Add breathers so the peaks read. |
125
- | "Backtracking reuses the space for free." | Repeated dead-end backtracking reads as padding. Use loops that return the player forward. |
126
- | "Players will figure the new mechanic out." | Not while it's killing them. Introduce it where it's safe, then develop/twist/combine. |
127
- | "Yellow paint everywhere so they see the ledges." | Only if yellow means *exactly* climbable and appears nowhere else. Inconsistent affordances lie. |
128
- | "The secret's hidden well — no one will find it." | A secret with no breadcrumb is just frustration. Show the thread; reward the curious eye. |
129
- | "The gap/cover/door width feels about right." | Guessing metrics breaks traversal later. Set the metrics block first; build to multiples. |
130
-
131
- ## Quick reference
132
-
133
- | Lever | Default | Where |
134
- |---|---|---|
135
- | Build order | blockout → greybox → playtest → art (art last) | `references/blockout-to-art.md` |
136
- | Metrics block | lock player height/jump/reach/cover first; build to multiples | `references/blockout-to-art.md` |
137
- | Navigation | one dominant landmark per area; legible critical path + breadcrumbed loops | `references/guidance-and-readability.md` |
138
- | Pacing | sawtooth: peak → breather (safe room) → higher peak | `references/pacing-and-encounters.md` |
139
- | Encounter teaching | introduce → develop → twist → combine | `references/pacing-and-encounters.md` |
140
- | Arena shape | sightline length matched to threat range; flanks + verticality | `references/pacing-and-encounters.md` |
141
- | Guidance | light leads; one reserved interact color; consistent affordances | `references/guidance-and-readability.md` |
142
- | Playtest | watch silent; log hesitation/lost/death/skip; read heatmaps | `references/guidance-and-readability.md` |
143
- | Secrets / risk | breadcrumb them; best optional reward behind biggest optional risk | `references/guidance-and-readability.md` |
104
+ | Making it look good first, then tuning the layout. | Art-first burns days reworking assets when the layout changes. Blockout, playtest, *then* art. |
105
+ | Trusting that it's "obvious where to go". | Obvious to *you*, the author. Fresh players get lost. Watch one before you believe it. |
106
+ | Patching confusion with a waypoint arrow or big text prompt. | That's a patch over a readability failure. Fix it with light, framing, and a landmark first. |
107
+ | Keeping the whole level intense because intensity is exciting. | Sustained peak = fatigue and it all flattens into noise. Add breathers so the peaks read. |
108
+ | Reusing the space by sending the player back the way they came. | Repeated dead-end backtracking reads as padding. Use loops that return the player forward. |
109
+ | Dropping a new mechanic in and expecting players to figure it out. | Not while it's killing them. Introduce it where it's safe, then develop/twist/combine. |
110
+ | Yellow paint everywhere so they see the ledges. | Only if yellow means *exactly* climbable and appears nowhere else. Inconsistent affordances lie. |
111
+ | Hiding a secret so well nobody finds it. | A secret with no breadcrumb is just frustration. Show the thread; reward the curious eye. |
112
+ | Eyeballing gap, cover, and door widths because they feel about right. | Guessing metrics breaks traversal later. Set the metrics block first; build to multiples. |
144
113
 
145
114
  ## Related skills
146
115
 
147
- - **`game-design`** — the systemic layer: mechanics, verbs, economy, progression, difficulty *systems*. Level design exercises those verbs in space; if the request is about the rules themselves, route there.
148
- - **`game-storytelling`** — narrative, quests, dialogue, and the meaning of environmental beats. Level design places the beat; storytelling authors it.
149
- - **`godot` / `unity` / `unreal`** — the engine tooling that *implements* a proven layout: nav meshes, occlusion, terrain/tilemap editors, lightmap/GI bakes, streaming, collision. Hand off here after the blockout plays well.
150
- - **`harness`** — the `02-DOCS` Karpathy-wiki this skill records level conventions into.
151
- - **References:** `references/blockout-to-art.md` (pipeline, metrics block, art handoff, playtesting the blockout); `references/pacing-and-encounters.md` (intensity graph, encounter template, arena patterns, difficulty curve); `references/guidance-and-readability.md` (light/color/composition, affordances, playtest protocol, telemetry, reward & secrets).
116
+ - `game-design` — the systemic layer: mechanics, verbs, economy, progression, difficulty *systems*. Level design exercises those verbs in space; if the request is about the rules themselves, route there.
117
+ - `game-storytelling` — narrative, quests, dialogue, and the meaning of environmental beats. Level design places the beat; storytelling authors it.
118
+ - `godot` / `unity` / `unreal` — the engine tooling that *implements* a proven layout: nav meshes, occlusion, terrain/tilemap editors, lightmap/GI bakes, streaming, collision. Hand off here after the blockout plays well.
119
+ - `harness` — the `02-DOCS` Karpathy-wiki this skill records level conventions into.
152
120
 
153
121
  ## Checklist
154
122
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spring-boot
3
- description: "Use when building, reviewing, testing, securing, or configuring a Spring Boot 4 / Spring Framework 7 backend — controllers, services, Spring Data JPA, application.yml, SecurityFilterChain, slice tests. Triggers: 'add a REST endpoint', 'wire up @Service and @Repository', 'my @Transactional isn't rolling back', 'LazyInitializationException after the session closed', 'N+1 select on a lazy collection', '@WebMvcTest + mock the service', 'migrate WebSecurityConfigurerAdapter', 'monta la seguridad con SecurityFilterChain', 'per què surt LazyInitializationException', a file importing org.springframework.boot.*, a pom.xml with spring-boot-starter-web, or an application.yml. NOT plain modern-Java language work like records/streams/virtual threads (that is java); NOT engine-level SQL schema/index/EXPLAIN (that is postgresdb); NOT container/CI mechanics (that is deployment)."
3
+ description: "Use when building, reviewing, testing, securing or configuring a Spring Boot 4 / Framework 7 backend — controllers, services, Spring Data JPA, application.yml, SecurityFilterChain, slice tests. NOT plain modern-Java language work like records or virtual threads (that is `java`); NOT engine-level SQL schema/index/EXPLAIN (that is `postgresdb`)."
4
4
  tags: [java, spring, jpa, security, backend]
5
5
  recommends: [java, postgresdb, secure-coding, deployment]
6
6
  origin: risco
@@ -23,47 +23,18 @@ If you are typing `WebSecurityConfigurerAdapter`, `@MockBean`, field `@Autowired
23
23
  `authorizeRequests`, or `javax.persistence` — **stop**. Those are the previous generation.
24
24
  The modern idioms below replace every one of them.
25
25
 
26
- ## When to use
27
-
28
- - Writing or reviewing any `@RestController`, `@Service`, `@Repository`, `@Component`,
29
- `@Configuration`, Spring Data JPA `@Entity`, or repository interface.
30
- - JPA persistence: entity mapping, `JpaRepository`, derived queries, `@Query`,
31
- `@Transactional` boundaries, fetch strategy / N+1, pagination.
32
- - Spring Security: `SecurityFilterChain`, method security, JWT resource server, OAuth2
33
- client, password encoding, CORS.
34
- - Configuration & profiles: `application.yml`, `@ConfigurationProperties`, `@Profile`,
35
- externalized secrets, `spring.config.import`.
36
- - Testing: `@SpringBootTest` vs slices (`@WebMvcTest`, `@DataJpaTest`), `@MockitoBean`,
37
- `MockMvc`, Testcontainers + `@ServiceConnection`.
38
-
39
- ## When NOT to use
26
+ ## Boundaries
40
27
 
41
28
  - Plain Java language work (records, sealed types, virtual threads, streams, pattern
42
- matching) with no Spring -> **`../java/SKILL.md`**.
43
- - Async Python FastAPI -> **`../fastapi/SKILL.md`**. NestJS/Node -> **`../nestjs/SKILL.md`**. Django -> `django`.
29
+ matching) with no Spring -> [`../java/SKILL.md`](../java/SKILL.md).
30
+ - Async Python FastAPI -> [`../fastapi/SKILL.md`](../fastapi/SKILL.md). NestJS/Node ->
31
+ [`../nestjs/SKILL.md`](../nestjs/SKILL.md). Django -> [`../django/SKILL.md`](../django/SKILL.md).
44
32
  - Engine-level SQL: schema/index design, `EXPLAIN`, partitioning, zero-downtime DDL ->
45
- **`../postgresdb/SKILL.md`** (this skill drives the JPA layer above it).
46
- - Language-agnostic injection/authz/secret theory -> **`../secure-coding/SKILL.md`**.
47
- - Dockerfile/Compose/CI/CD mechanics -> **`../deployment/SKILL.md`** (keep only a build note here).
48
-
49
- ## Decision rules
50
-
51
- 1. **Constructor injection only — final fields, no `@Autowired` on fields.** A class whose
52
- collaborators are constructor args is testable with `new` and fails fast on a missing bean.
53
- 2. **Controller stays thin: parse, validate, delegate, map.** Any branch with business
54
- meaning belongs in the service, where it is transactional and unit-testable without MVC.
55
- 3. **`@Transactional` lives on service methods, never on a controller or repository.** The
56
- transaction must wrap the unit of work, not the HTTP request or a single query.
57
- 4. **Expose DTO records in and out — never the `@Entity`.** Returning an entity leaks columns
58
- and triggers lazy loads inside the JSON serializer (the classic `LazyInitializationException`).
59
- 5. **Typed `@ConfigurationProperties` record over scattered `@Value`.** One validated binding
60
- beats string keys sprinkled across the codebase and gives you a fail-fast startup.
61
- 6. **Security is a `SecurityFilterChain` bean with the lambda DSL** — `authorizeHttpRequests`
62
- + `requestMatchers`. `WebSecurityConfigurerAdapter`, `authorizeRequests`, `antMatchers` are gone.
63
- 7. **Reach for the narrowest test slice first.** `@WebMvcTest` for a controller,
64
- `@DataJpaTest` for a repository; `@SpringBootTest` only when you genuinely need the full context.
65
- 8. **Validate at the edge with `@Valid` + Bean Validation (`jakarta.validation`).** Reject
66
- bad input before it reaches the service so business code assumes valid data.
33
+ [`../postgresdb/SKILL.md`](../postgresdb/SKILL.md) (this skill drives the JPA layer above it).
34
+ - Language-agnostic injection/authz/secret theory ->
35
+ [`../secure-coding/SKILL.md`](../secure-coding/SKILL.md).
36
+ - Dockerfile/Compose/CI/CD mechanics -> [`../deployment/SKILL.md`](../deployment/SKILL.md)
37
+ (keep only a build note here).
67
38
 
68
39
  ## Project layout
69
40
 
@@ -84,9 +55,12 @@ com.acme.shop
84
55
 
85
56
  ## Controllers
86
57
 
87
- `@RestController` + DTO records, `@Valid` on the body, `ResponseEntity` for 201/`Location`,
88
- a `@RestControllerAdvice` for one error envelope. Boot 4 adds first-class versioning via a
89
- `version` attribute on the mapping — one controller serves many versions, no path duplication.
58
+ `@RestController` + DTO records, `@Valid` on the body (Bean Validation, `jakarta.validation`)
59
+ so business code can assume valid data, `ResponseEntity` for 201/`Location`, a
60
+ `@RestControllerAdvice` for one error envelope. The controller parses, validates, delegates
61
+ and maps — any branch with business meaning belongs in the service, where it is transactional
62
+ and unit-testable without MVC. Boot 4 adds first-class versioning via a `version` attribute
63
+ on the mapping — one controller serves many versions, no path duplication.
90
64
 
91
65
  ```java
92
66
  @RestController
@@ -120,7 +94,7 @@ class ApiExceptionHandler {
120
94
  record ApiError(String code, String message, List<String> details) {}
121
95
  ```
122
96
 
123
- **Bad -> Good** — never return the entity:
97
+ **Bad -> Good** — never return the entity; it leaks columns and lazy-loads in the serializer:
124
98
 
125
99
  ```java
126
100
  // Bad: leaks columns; lazy fields blow up in the serializer after the tx closes.
@@ -132,7 +106,9 @@ record ApiError(String code, String message, List<String> details) {}
132
106
  ## Service + transactions
133
107
 
134
108
  Constructor-injected, `final` fields, `@Transactional` on the write path, `readOnly = true`
135
- on queries (lets Hibernate skip dirty checking).
109
+ on queries (lets Hibernate skip dirty checking). `@Transactional` belongs on service methods,
110
+ never on a controller or repository: the transaction must wrap the unit of work, not the HTTP
111
+ request or a single query.
136
112
 
137
113
  ```java
138
114
  @Service
@@ -233,11 +209,13 @@ record AppProperties(Duration inviteTtl, int maxOrdersPerDay) {} // typed, val
233
209
  ```
234
210
 
235
211
  **Bad -> Good** — scattered `@Value("${app.max-orders-per-day}")` strings vs one injected
236
- `AppProperties` record. Typed binding fails fast on a missing/mistyped key instead of NPE-ing later.
212
+ `AppProperties` record. One typed binding beats string keys sprinkled across the codebase and
213
+ fails fast on a missing/mistyped key instead of NPE-ing later.
237
214
 
238
215
  ## Security
239
216
 
240
- A single `SecurityFilterChain` bean, stateless for token APIs, JWT via the resource server.
217
+ A single `SecurityFilterChain` bean with the lambda DSL, stateless for token APIs, JWT via the
218
+ resource server.
241
219
 
242
220
  ```java
243
221
  @Configuration
@@ -264,11 +242,12 @@ Order `requestMatchers` from most specific to least — the first match wins, so
264
242
  `permitAll` placed early opens routes you meant to lock. Full JWT/OAuth2 client, method
265
243
  security, CORS, and CSRF posture (token vs cookie apps) live in
266
244
  [`references/security.md`](references/security.md). For the language-agnostic authz/secret
267
- principles behind these rules, see `../secure-coding/SKILL.md`.
245
+ principles behind these rules, see [`../secure-coding/SKILL.md`](../secure-coding/SKILL.md).
268
246
 
269
247
  ## Testing
270
248
 
271
- Pick the narrowest slice that exercises what you changed:
249
+ Pick the narrowest slice that exercises what you changed — `@SpringBootTest` only when you
250
+ genuinely need the full context:
272
251
 
273
252
  | Slice | Loads | Use for | Collaborators |
274
253
  |---|---|---|---|
@@ -324,14 +303,17 @@ interface BillingClient {
324
303
  `@Retryable` and `@ConcurrencyLimit` are core in Framework 7 — no extra Spring Retry
325
304
  dependency for the basics.
326
305
 
327
- ## Anti-patterns / rationalizations -> STOP
306
+ ## Anti-patterns
328
307
 
329
- | You are about to... | Why it's wrong | Do instead |
308
+ | Anti-pattern | Why it's wrong | Do instead |
330
309
  |---|---|---|
331
310
  | Extend `WebSecurityConfigurerAdapter` | Removed in Security 6/7 | `SecurityFilterChain` bean + lambda DSL |
332
311
  | `@Autowired` on a field | Untestable, hides missing beans till runtime | constructor injection, `final` fields |
333
312
  | `@Transactional` on a `@RestController` | Tx must wrap the unit of work, not the request | put it on the service method |
313
+ | Business branching in the controller | Not transactional, needs MVC to test | move the decision into the `@Service` |
334
314
  | Return the `@Entity` from a controller | Leaks columns, lazy-loads in serializer (LIE) | map to a DTO record inside the tx |
315
+ | Request body reaching the service unvalidated | Business code can no longer assume valid data | `@Valid` + `jakarta.validation` at the edge |
316
+ | Scattered `@Value("${...}")` config keys | String keys, no validation, fails late | one typed `@ConfigurationProperties` record |
335
317
  | Use `@MockBean` / `@SpyBean` | Replaced in Boot 4 | `@MockitoBean` / `@MockitoSpyBean` |
336
318
  | `import javax.persistence` / `javax.validation` | Jakarta EE 11 baseline | `jakarta.*` |
337
319
  | `authorizeRequests` / `antMatchers` | Gone in Security 6/7 | `authorizeHttpRequests` + `requestMatchers` |
@@ -341,6 +323,8 @@ dependency for the basics.
341
323
  | `catch (Exception e)` and echo `e.getMessage()` | Leaks internals, swallows bugs | `@RestControllerAdvice` + typed error envelope |
342
324
  | Serialize a lazy collection after the tx closes | `LazyInitializationException` / N+1 | fetch join or `@EntityGraph`, map in-tx |
343
325
 
326
+ `scripts/verify.sh` greps a project for the legacy idioms above (read-only, best effort).
327
+
344
328
  ## Quick reference
345
329
 
346
330
  | Task | Idiom |
@@ -364,12 +348,3 @@ If the repo has a `02-DOCS/` wiki, record stack decisions (Boot version, securit
364
348
  test strategy, migration tool) in `02-DOCS/wiki/stack/spring-boot.md` and link it from the
365
349
  `CLAUDE.md` Knowledge map. This is recorded, not gated — if there is no `02-DOCS/`, skip
366
350
  silently; you may suggest the project harness if the user wants persistent docs.
367
-
368
- ## See also
369
-
370
- - `../java/SKILL.md` — the language underneath (records, virtual threads, streams).
371
- - `../postgresdb/SKILL.md` — the engine under JPA (schema, indexes, `EXPLAIN`).
372
- - `../secure-coding/SKILL.md` — the authz/injection/secret principles behind the security rules.
373
- - `../deployment/SKILL.md` — packaging the jar, container, CI.
374
- - [`references/jpa.md`](references/jpa.md) · [`references/security.md`](references/security.md) · [`references/testing.md`](references/testing.md)
375
- - `scripts/verify.sh` — best-effort static reviewer for legacy Spring idioms.
@@ -4,7 +4,7 @@ should_trigger:
4
4
  - prompt: "Add a REST endpoint to create an order in our Spring Boot service."
5
5
  why: "Core controller/service work — the central job of the skill."
6
6
  - prompt: "My @Transactional method isn't rolling back when it throws, why?"
7
- why: "Non-obvious proxy self-invocation + checked-exception-no-rollback rule; a defining Spring trap."
7
+ why: "Non-obvious proxy self-invocation + checked-exception-no-rollback trap; documented in the service/transactions section."
8
8
  - prompt: "I get LazyInitializationException when the JSON serializer reads the response."
9
9
  why: "Classic JPA fetch/session-boundary symptom; the fix is map-to-DTO-in-tx, a core rule here."
10
10
  - prompt: "Migra esta config de seguridad, usa WebSecurityConfigurerAdapter y está deprecada."
@@ -12,7 +12,7 @@ should_trigger:
12
12
  - prompt: "Set up a @WebMvcTest for the controller and mock the service."
13
13
  why: "Slice testing + @MockitoBean — non-obvious that @MockBean is the wrong (removed) idiom."
14
14
  - prompt: "Configura @ConfigurationProperties con perfiles para esta app."
15
- why: "Catalan/Spanish; typed config + profiles is a named decision rule."
15
+ why: "Catalan/Spanish; typed @ConfigurationProperties + profiles is a documented config surface."
16
16
  - prompt: "We have N+1 selects on a lazy collection — how do I fetch-join it?"
17
17
  why: "JPA fetch strategy / @EntityGraph, a documented depth area."
18
18
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: together-fireworks
3
- description: "Use when calling hosted open-model inference on Together AI or Fireworks AI — pointing the OpenAI SDK at api.together.ai or api.fireworks.ai, picking an open model (Llama, DeepSeek, Qwen, GPT-OSS) and what it costs, or cutting the bill with batch inference. Triggers: 'call DeepSeek/Llama on Together', 'wire the OpenAI SDK to Fireworks', 'why is my model name 404ing', 'which open-source model and how much per million tokens', 'halve my LLM bill with batch', 'move off GPT-4 to a cheaper open-weights endpoint', 'serverless vs dedicated for sustained QPS', '¿qué modelo open source uso y cuánto cuesta?', 'abaratar la factura de inferència'. NOT renting raw GPUs to self-host weights (that is runpod), NOT running a model locally with zero marginal cost (that is ollama)."
3
+ description: "Use when calling open-weight LLMs on Together AI or Fireworks AI's OpenAI-compatible endpoints — `base_url` plus namespaced model id, the cheapest model that clears the bar, per-1M-token cost math, serverless vs batch vs dedicated. NOT renting GPUs to self-host weights (that is `runpod`), NOT running a model locally for free (that is `ollama`)."
4
4
  tags: [llm, inference, together-ai, fireworks-ai, openai-compatible, open-models, batch, cost]
5
5
  recommends: [runpod, modal, ollama, huggingface, fal, cost-tracking, llm-pipeline, prompt-engineering, embeddings-search]
6
6
  origin: risco
@@ -107,7 +107,7 @@ Fuller catalog and embedding/fine-tuning numbers: `references/models-and-pricing
107
107
 
108
108
  Decision: **real-time → serverless. Big offline job (eval, synthetic data, bulk classify) → batch. Sustained heavy traffic with an SLA → dedicated.**
109
109
 
110
- > **Gotcha — Together batch is NOT the OpenAI Batch endpoint.** Together's OpenAI-compat layer does **not** expose `/v1/batches`. Use Together's **native Batch API**: upload a JSONL file, default **24h** window, up to **50,000 requests/file**, up to **50% off**, separate rate-limit pool. Pointing the OpenAI Batch client at Together fails. Fireworks instead exposes Batch as a serving *path* through the one API (Serverless 2.0: Standard / Priority / Batch), batch = 50% of serverless. See `references/batch-and-tuning.md`.
110
+ > **Gotcha — Together batch is NOT the OpenAI Batch endpoint.** Together's OpenAI-compat layer does **not** expose `/v1/batches`. Use Together's **native Batch API**: upload a JSONL file, default **24h** window, up to **50,000 requests/file**, up to **50% off**, separate rate-limit pool. Pointing the OpenAI Batch client at Together fails. Fireworks instead exposes Batch as a serving *path* through the one API (Serverless 2.0: Standard / Priority / Batch), batch = 50% of serverless. JSONL shape, the upload/poll/download flow, limits, and dedicated-deployment notes: `references/batch-and-tuning.md`.
111
111
 
112
112
  Two more Fireworks multipliers worth knowing:
113
113
  - **Cached input tokens default to 50%** of input price (text/vision models) — repeated prefixes get cheaper automatically.
@@ -173,9 +173,4 @@ Keep the id mapping in config, not in `if provider == ...` branches scattered th
173
173
  | Treating these like free/local | They bill per token; ollama is the zero-marginal-cost path | If cost must be zero and weights run on your box → `../ollama/SKILL.md` |
174
174
  | Renting GPUs to "save money" then idling them | A serverless token endpoint has no idle cost | Self-host only at sustained scale → `../runpod/SKILL.md` |
175
175
 
176
- ## References
177
-
178
- - `references/models-and-pricing.md` — fuller per-provider model + pricing tables, embeddings, fine-tuning costs, with a re-check note.
179
- - `references/batch-and-tuning.md` — Together native Batch API JSONL shape + upload/poll/download flow and limits; Fireworks batch path; dedicated deployment notes.
180
-
181
176
  Validate any inference snippet/config with `scripts/verify.sh <file-or-dir>` — a static, no-network lint for the right base URLs, namespaced model ids, and env-var keys.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: youtube-api
3
- description: "Use when connecting a real YouTube channel to code via the Data API v3 (uploads, metadata) and Analytics API v2 (performance) — OAuth, resumable video upload, editing title/description/tags/privacy after publish, pulling views/watch time/averageViewPercentage/retention/traffic sources — and logging that performance into 02-DOCS/wiki/youtube/ as a dated feedback log. Triggers: 'upload a video to my channel via the API and set its tags', 'videos.insert returns 403 quotaExceeded / uploadLimitExceeded', 'my YouTube refresh token keeps dying after about 7 days', 'pull the audienceWatchRatio retention curve for video X', 'fetch this month's traffic sources and write them into the wiki', 'subir vídeos a YouTube por API y guardar las estadísticas del canal', 'treure les estadístiques del canal i guardar-les al wiki'. NOT what-to-publish or how-to-package it (that is youtube-strategy / youtube-packaging)."
3
+ description: "Use when wiring code to a real YouTube channel: user OAuth 2.0, resumable videos.insert uploads, editing metadata after publish, pulling views/watch time/retention/traffic from the Analytics API v2 into a dated 02-DOCS/wiki/youtube/ feedback log. NOT what to publish or how to title and thumbnail it (that is youtube-strategy / youtube-packaging)."
4
4
  tags: [youtube, youtube-data-api, youtube-analytics-api, oauth2, resumable-upload, video-metadata, audience-retention, channel-feedback-log]
5
5
  recommends: [social-publisher, api-connector-builder, automation-flows, knowledge-ops]
6
6
  origin: risco
@@ -17,31 +17,20 @@ YouTube has **two separate APIs** and you will touch both:
17
17
 
18
18
  Auth is **user OAuth 2.0, not a service account.** A human owns the channel; you act on their behalf with a refresh token. A service account cannot own a YouTube channel — if you reach for one, stop. (Service-account Google auth for Gmail/Drive/Sheets is `google-workspace`, a different model.)
19
19
 
20
- ## When to use / When NOT
21
-
22
- Use when:
23
-
24
- - Wiring a script or agent to upload to a channel (`videos.insert`), set metadata, schedule a publish, or set a custom thumbnail.
25
- - Editing an existing video's title/description/tags/privacy after publish (`videos.update`).
26
- - Pulling channel or per-video stats: views, `estimatedMinutesWatched`, `averageViewPercentage`, the audience-retention curve, the traffic-source breakdown.
27
- - Building the recurring "fetch performance → write to `02-DOCS/wiki/youtube/`" loop that turns API responses into a channel feedback log.
28
- - Debugging `403 quotaExceeded`, `uploadLimitExceeded` (429), `401 invalid_credentials`, scope errors, or a refresh token that dies after a week.
29
-
30
- Do NOT use when (route to the sibling that owns it):
20
+ Route elsewhere when the job is not transport:
31
21
 
32
22
  | You actually want | Go to |
33
23
  | --- | --- |
34
- | What videos to make / niche / cadence / growth plan | `youtube-strategy` *(catalog id)* |
35
- | Video ideas, hooks, a topic backlog | `youtube-ideation` *(catalog id)* |
36
- | Title + thumbnail packaging, CTR copy, A/B framing | `youtube-packaging` *(catalog id)* |
24
+ | What videos to make / niche / cadence / growth plan | `../youtube-strategy/SKILL.md` |
25
+ | Video ideas, hooks, a topic backlog | `../youtube-ideation/SKILL.md` |
26
+ | Title + thumbnail packaging, CTR copy, A/B framing | `../youtube-packaging/SKILL.md` |
37
27
  | The thumbnail image itself | `../youtube-thumbnails/SKILL.md` |
38
28
  | Render/produce the actual video file in code | `../remotion-video/SKILL.md` |
39
29
  | Post one asset across many networks at once | `../social-publisher/SKILL.md` |
40
- | Wrap an arbitrary REST provider with OAuth + retries | `api-connector-builder` *(catalog id)* |
41
- | Chain upload → Notion row → Slack across tools | `automation-flows` *(catalog id)* |
42
- | Service-account auth to Gmail/Drive/Sheets | `google-workspace` *(catalog id)* |
43
-
44
- One line: **this skill authenticates, calls, and ingests the two YouTube APIs into the wiki. What to publish and how to package it belong to the youtube-strategy / youtube-ideation / youtube-packaging siblings.**
30
+ | Wrap an arbitrary REST provider with OAuth + retries | `../api-connector-builder/SKILL.md` |
31
+ | Chain upload → Notion row → Slack across tools | `../automation-flows/SKILL.md` |
32
+ | Service-account auth to Gmail/Drive/Sheets | `../google-workspace/SKILL.md` |
33
+ | Generic wiki structure and conventions | `../knowledge-ops/SKILL.md` |
45
34
 
46
35
  ## 1. One-time setup (do this before any code)
47
36
 
@@ -151,7 +140,7 @@ video_id = resp["id"]
151
140
  data.thumbnails().set(videoId=video_id, media_body=MediaFileUpload("ep14.jpg")).execute()
152
141
  ```
153
142
 
154
- Two separate limits, not one — and uploads no longer come out of the 10k unit pool. As of the official quota docs (Last updated 2026-06-01 UTC, `https://developers.google.com/youtube/v3/getting-started`), a project's default allocation is *"100 search.list calls, 100 videos.insert calls, and 10,000 units per day combined for all other endpoints."* So `videos.insert` has its **own dedicated cap of ~100 uploads/day**, charged against that allocation rather than spending ~1,600 units of the 10k pool like the older model. That ~100/day call cap is exactly what trips `uploadLimitExceeded` (429) while your 10k unit pool still looks untouched. Throttle the upload **count** against the 100/day allocation, not just the unit spend — space automated uploads out and back off on 429.
143
+ Throttle the upload **count**, not the unit spend: `videos.insert` has its own cap of ~100 uploads/day, so `uploadLimitExceeded` (429) hits while the 10k unit pool still looks untouched. Space automated uploads out and back off on 429 — figures and citation in §7.
155
144
 
156
145
  ## 4. Edit metadata after publish
157
146
 
@@ -254,7 +243,7 @@ Rule: **append, never overwrite.** The feedback log *is* the value — overwriti
254
243
  | `*.list` read | 1–5 units (from the 10k pool) |
255
244
  | Analytics `reports.query` | (separate Analytics quota) |
256
245
 
257
- Per the official docs (Last updated 2026-06-01 UTC, `https://developers.google.com/youtube/v3/getting-started`; per-method costs at `https://developers.google.com/youtube/v3/determine_quota_cost`), a project's default allocation is **100 `search.list` calls + 100 `videos.insert` calls + 10,000 units/day combined for all other endpoints**. Uploads and search each draw on their *own* daily call cap; everything else (writes, reads) spends the shared 10k-unit pool. All quotas reset at midnight Pacific. This is a change from the older single-pool model where `videos.insert` cost ~1,600 units — confirm the live figure on the quota-cost page before relying on it, since Google notes the allocation "is subject to change."
246
+ Per the official docs (Last updated 2026-06-01 UTC, `https://developers.google.com/youtube/v3/getting-started`; per-method costs at `https://developers.google.com/youtube/v3/determine_quota_cost`), a project's default allocation is *"100 search.list calls, 100 videos.insert calls, and 10,000 units per day combined for all other endpoints."* All quotas reset at midnight Pacific. This is a change from the older single-pool model where `videos.insert` cost ~1,600 units — confirm the live figure on the quota-cost page before relying on it, since Google notes the allocation "is subject to change."
258
247
 
259
248
  On `403 quotaExceeded` / `rateLimitExceeded` or `429`: **exponential backoff with jitter**, then stop for the day on a hard quota cap — retrying a daily-quota 403 in a tight loop just burns the next day too.
260
249
 
@@ -281,11 +270,3 @@ Error → cause map:
281
270
  | Treat the 10k unit pool as the upload budget | Uploads use a separate ~100/day call cap, so `uploadLimitExceeded` 429 hits with the pool untouched | Throttle upload count against the ~100/day cap |
282
271
  | Overwrite yesterday's wiki snapshot | Destroys the trend the siblings read | Append a new dated entry every pull |
283
272
  | Leave the app in "Testing" | Token silently dies in 7 days | Publish to "In production" |
284
-
285
- ## Cross-references
286
-
287
- - `../youtube-thumbnails/SKILL.md` — the thumbnail image this skill only *sets*.
288
- - `../social-publisher/SKILL.md` — when the asset goes to many networks, not just YouTube.
289
- - `../remotion-video/SKILL.md` — produce the video file this skill uploads.
290
- - `youtube-strategy`, `youtube-ideation`, `youtube-packaging` *(catalog ids)* — what the numbers *mean* and what to do next.
291
- - `api-connector-builder`, `automation-flows`, `knowledge-ops` *(catalog ids)* — generic connector wrapping, cross-tool chaining, and wiki conventions.