@ericrisco/rsc 0.1.56 → 0.1.58

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.56",
2
+ "version": "0.1.58",
3
3
  "counts": {
4
4
  "skills": 258
5
5
  },
@@ -2065,7 +2065,7 @@
2065
2065
  },
2066
2066
  {
2067
2067
  "id": "github-actions",
2068
- "description": "Use when authoring or fixing GitHub Actions CI/CD — workflows under .github/workflows, jobs, the runner matrix, dependency caching, secrets and OIDC cloud deploys, environments and approval gates, reusable and composite workflows. Triggers: 'write a CI workflow', 'my GitHub Actions builds are slow / add caching', 'run the tests on a matrix of node versions', 'deploy to AWS without storing access keys' (OIDC), 'every push spawns a run and the old ones keep finishing' (concurrency), 'pin my actions / supply-chain hardening after the tj-actions thing', 'munta el desplegament continu amb GitHub Actions cap a producció', 'per què el GITHUB_TOKEN té permisos d'escriptura per defecte'. NOT writing the Dockerfile or image build strategy (that is docker), NOT the branching/merge model (that is git-workflow), NOT release readiness or the changelog (that is ship).",
2068
+ "description": "Use when authoring or fixing GitHub Actions CI/CD — workflows under .github/workflows, triggers, job matrix, caching, token permissions, OIDC cloud deploys, environment gates, reusable workflows. NOT the Dockerfile or image build strategy (that is `docker`), NOT the branching model (that is `git-workflow`), NOT release readiness (that is `ship`).",
2069
2069
  "tags": [
2070
2070
  "github-actions",
2071
2071
  "ci-cd",
@@ -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",
@@ -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",
@@ -2789,7 +2789,7 @@
2789
2789
  },
2790
2790
  {
2791
2791
  "id": "market-research",
2792
- "description": "Use when you need a defensible picture of a MARKET as a whole — sizing it with TAM/SAM/SOM, cutting it into reachable segments, and proving demand is real and moving — with a dated source behind every number. Triggers: 'how big is the market for X', 'size this market', 'what's our TAM', 'is there real demand for this', 'who are the segments', 'where's the beachhead', 'sanity-check this TAM before the raise', 'top-down or bottom-up', '¿qué tamaño tiene el mercado de X', 'calcula el TAM', 'hay demanda real para esto', 'quina mida té aquest mercat'. NOT profiling specific named rivals and their moves (that is competitor-watch), NOT building a named list of accounts to sell to (that is lead-gen).",
2792
+ "description": "Use when a MARKET as a whole needs a defensible picture — TAM/SAM/SOM sized top-down AND bottom-up until the two converge, cut into reachable segments with one named beachhead, demand proven real, and a dated source behind every figure. NOT profiling named rivals and their moves (that is `competitor-watch`), NOT building a list of accounts to sell to (that is `lead-gen`).",
2793
2793
  "tags": [
2794
2794
  "market-research",
2795
2795
  "tam-sam-som",
@@ -3033,7 +3033,7 @@
3033
3033
  },
3034
3034
  {
3035
3035
  "id": "nestjs",
3036
- "description": "Use when building or structuring a NestJS backend — feature modules, providers, controllers, DI wiring, and the cross-cutting layer (guards, interceptors, pipes, exception filters) — including binding-scope and request-lifecycle decisions and Nest-specific testing. Triggers: 'create a NestJS module', 'wire a custom provider with useFactory', 'APP_GUARD vs @UseGuards on the controller', 'my request-scoped provider is undefined in a guard', 'A circular dependency has been detected at bootstrap', 'mock a repository provider with overrideProvider', 'monta un módulo de Nest', 'guard de autenticación JWT en NestJS'. NOT a bare Express/Node service with no DI (that is nodejs).",
3036
+ "description": "Use when building or structuring a NestJS backend — feature modules, providers and DI wiring, provider scopes and request-lifecycle order, where to bind guards/pipes/interceptors/filters, and testing with Test.createTestingModule. NOT a bare Express/Fastify service with no DI (that is `nodejs`), NOT framework-agnostic REST design (that is `api-design`).",
3037
3037
  "tags": [
3038
3038
  "nestjs",
3039
3039
  "nodejs",
@@ -3158,7 +3158,7 @@
3158
3158
  },
3159
3159
  {
3160
3160
  "id": "nodejs",
3161
- "description": "Use when building or structuring a plain Node.js / Express backend service — project layout, async correctness, central error handling, config validation, and graceful shutdown — the runtime and HTTP service, not a DI framework. Triggers: 'set up an Express 5 service', 'my async route error returns 200 with an empty body', 'where do controllers vs services go', 'centralize error handling middleware', 'shut down cleanly on SIGTERM without dropping requests', 'why does one unhandled promise rejection crash my server', 'monta un backend con Express y manejo de errores', 'apaga el servidor sin perder peticiones en vuelo'. NOT NestJS DI/modules/guards (that is nestjs); NOT the TS type system/tsconfig (that is typescript); NOT REST contract/versioning (that is api-design).",
3161
+ "description": "Use when building or operating a plain Node.js / Express 5 backend service: project layout, async correctness, central error middleware, fail-fast config, graceful shutdown on SIGTERM. NOT DI modules/providers/guards (that is `nestjs`), NOT the type system or tsconfig (that is `typescript`), NOT REST contract design (that is `api-design`).",
3162
3162
  "tags": [
3163
3163
  "nodejs",
3164
3164
  "express",
@@ -3546,7 +3546,7 @@
3546
3546
  },
3547
3547
  {
3548
3548
  "id": "prisma-orm",
3549
- "description": "Use when modeling data or writing type-safe queries with Prisma ORM in TypeScript and hitting its classic problems: N+1 on relations, over-fetching with fat include, an unbounded findMany scanning the whole table, the v7 'requires either adapter or accelerateUrl' error, or a Prisma 6 to 7 upgrade. Owns schema.prisma, the prisma-client generator, prisma.config.ts, the Prisma Client query API, and Prisma Migrate. Triggers: 'PrismaClient requires either adapter or accelerateUrl', 'client is not in node_modules anymore', 'relationLoadStrategy join vs query', 'migrate dev vs migrate deploy in CI', 'findMany returns the whole table', 'modela el esquema de usuarios y pedidos con Prisma', 'migració de Prisma a la versió 7'. NOT the schema-as-TS SQL-builder ORM (that is drizzle-orm), NOT cross-cutting zero-downtime migration strategy (that is db-migrations), NOT Postgres server tuning and EXPLAIN (that is postgresdb).",
3549
+ "description": "Use when modeling data or writing type-safe queries with Prisma ORM in TypeScript — `schema.prisma`, `prisma.config.ts`, the generated Prisma Client, and Prisma Migrate, including the v6 to v7 upgrade. NOT schema-as-TS with a SQL builder (that is `drizzle-orm`), NOT ORM-agnostic zero-downtime migration (that is `db-migrations`), NOT Postgres engine tuning (that is `postgresdb`).",
3550
3550
  "tags": [
3551
3551
  "prisma",
3552
3552
  "prisma-orm",
@@ -3571,7 +3571,7 @@
3571
3571
  },
3572
3572
  {
3573
3573
  "id": "procurement",
3574
- "description": "Use when a small operator must decide what to buy and from whom — pick a supplier/vendor, write an RFI/RFQ/RFP that gets comparable bids back, compare quotes on total cost not sticker price, negotiate price and payment terms, judge single-source risk, or build a vendor scorecard for quarterly review. Triggers: 'help me pick a supplier for X', 'write an RFQ for 5,000 units', 'which of these quotes is actually cheapest over three years', 'should I take the 2/10 net 30 early-payment discount', 'we buy a critical part from one supplier — how risky is that', 'build a supplier scorecard', 'compara estos proveedores / negociar condiciones de pago', 'compara aquests proveïdors / negociar condicions amb el proveïdor'. NOT signing the binding purchase agreement or redlining liability/IP clauses (that is contracts), NOT the price you charge your own customers (that is pricing), NOT counting or reordering the stock once it arrives (that is inventory).",
3574
+ "description": "Use when a small operator must choose what to buy and from whom: pick a supplier, write an RFI/RFQ/RFP that returns comparable bids, score quotes on total cost of ownership, negotiate price and payment terms, or judge single-source risk. NOT redlining the purchase agreement (that is `contracts`), NOT the price you charge customers (that is `pricing`), NOT stock once it lands (that is `inventory`).",
3575
3575
  "tags": [
3576
3576
  "procurement",
3577
3577
  "sourcing",
@@ -3884,7 +3884,7 @@
3884
3884
  },
3885
3885
  {
3886
3886
  "id": "reporting",
3887
- "description": "Use when you need a recurring report that ships to stakeholders on a cadence — a weekly team digest, monthly exec pack, quarterly board summary, or recurring client performance report — and it must go out reliably without a human in the loop. Symptoms: a standing metrics email keeps breaking or shows stale numbers, the Monday digest is hand-assembled every week, leadership asks for 'the same report but every month', or a client expects a PDF on a schedule. Triggers: 'set up a weekly automated report emailed to the exec team', 'build a monthly PDF report for our biggest client on a schedule', 'send the board a quarterly summary every quarter', 'our Monday metrics email keeps going out with last week's numbers — make it reliable', 'automatiza un informe mensual para dirección', 'munta un informe setmanal automàtic per al comitè'. NOT a live screen people open to slice metrics (that is dashboard), NOT deciding which KPIs to track (that is kpi-framework), NOT a one-off investigation (that is analytics).",
3887
+ "description": "Use when a recurring report must ship itself on a cadence — weekly digest, monthly exec pack, board pack — via a fetch→narrate→render→deliver pipeline with a schedule and a freshness gate. NOT a live view people slice (that is `dashboard`), NOT picking which KPIs to track (that is `kpi-framework`), NOT a one-off investigation (that is `analytics`).",
3888
3888
  "tags": [
3889
3889
  "reporting",
3890
3890
  "automated-reports",
@@ -4013,7 +4013,7 @@
4013
4013
  },
4014
4014
  {
4015
4015
  "id": "ruby",
4016
- "description": "Use when writing idiomatic Ruby outside Rails — plain scripts, CLIs, gems, libraries — or refactoring imperative loops into Enumerable chains, designing module mixins, packaging with Bundler, deciding whether metaprogramming is worth it, or setting up Minitest/RSpec. Triggers: 'write this in Ruby', 'refactor this loop with map/reduce', 'build a gem', 'gemspec / Gemfile.lock', 'method_missing or define_method?', 'Minitest vs RSpec', 'FrozenError after Ruby 3.4 upgrade', 'mixin vs inheritance', 'escribir una gema en Ruby', 'refactoritzar amb blocs'. NOT Rails/ActiveRecord/controllers (that is rails).",
4016
+ "description": "Use when writing or refactoring plain Ruby outside Rails — scripts, CLIs, gems, libraries: Enumerable chains and blocks, module mixins and value objects, Bundler/gemspec packaging, whether metaprogramming earns its keep, Minitest or RSpec, Ruby 3.4/4.0 frozen-string hygiene. NOT Rails, ActiveRecord, or ActiveSupport idioms (that is `rails`).",
4017
4017
  "tags": [
4018
4018
  "ruby",
4019
4019
  "gems",
@@ -4273,7 +4273,7 @@
4273
4273
  },
4274
4274
  {
4275
4275
  "id": "shortform-ideation",
4276
- "description": "Use when an account that already posts (or is about to start posting) Reels/TikTok/Shorts needs a ranked batch of next video ideas grounded in its own performance log plus live trending sounds/formats/hashtags, and a ledger that ties each idea-bet to its measured outcome. Use to fold this week's trending audio into ideas, to decide which 3 of 12 ideas to shoot first, or to review why the bets you made flopped. Triggers: 'give me 10 Reels ideas for next week', 'which of these ideas do we make first', 'fold this week's trending TikTok sounds into our idea list', 'why did the ones we bet on last month flop', 'idea backlog for our TikTok', 'idéame Reels para esta semana basándote en lo que ya nos funcionó', 'prioritza idees de vídeo curt per aquesta setmana'. NOT writing the shot-by-shot script or edit decision sheet for a chosen idea (that is video-shorts), NOT setting cadence/pillars/positioning (that is shortform-strategy), NOT captions/covers/hashtag-sets for a finished cut (that is shortform-packaging).",
4276
+ "description": "Use when a Reels/TikTok/Shorts account needs its next video ideas scored into a ranked backlog, grounded in its own performance log plus dated trending sounds, each bet logged so its outcome feeds the next batch. NOT scripting a chosen idea (that is `video-shorts`), NOT pillars or cadence (that is `shortform-strategy`), NOT packaging a finished cut (that is `shortform-packaging`).",
4277
4277
  "tags": [
4278
4278
  "shortform",
4279
4279
  "reels",
@@ -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.56",
3
+ "version": "0.1.58",
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: github-actions
3
- description: "Use when authoring or fixing GitHub Actions CI/CD — workflows under .github/workflows, jobs, the runner matrix, dependency caching, secrets and OIDC cloud deploys, environments and approval gates, reusable and composite workflows. Triggers: 'write a CI workflow', 'my GitHub Actions builds are slow / add caching', 'run the tests on a matrix of node versions', 'deploy to AWS without storing access keys' (OIDC), 'every push spawns a run and the old ones keep finishing' (concurrency), 'pin my actions / supply-chain hardening after the tj-actions thing', 'munta el desplegament continu amb GitHub Actions cap a producció', 'per què el GITHUB_TOKEN té permisos d'escriptura per defecte'. NOT writing the Dockerfile or image build strategy (that is docker), NOT the branching/merge model (that is git-workflow), NOT release readiness or the changelog (that is ship)."
3
+ description: "Use when authoring or fixing GitHub Actions CI/CD — workflows under .github/workflows, triggers, job matrix, caching, token permissions, OIDC cloud deploys, environment gates, reusable workflows. NOT the Dockerfile or image build strategy (that is `docker`), NOT the branching model (that is `git-workflow`), NOT release readiness (that is `ship`)."
4
4
  tags: [github-actions, ci-cd, workflows, oidc, caching]
5
5
  recommends: [docker, git-workflow, ship, deployment, secure-coding, aws-essentials, vercel]
6
6
  origin: risco
@@ -10,26 +10,16 @@ origin: risco
10
10
 
11
11
  A workflow is config that runs on an event. Before you write a single step, decide three things: **which events** fire the workflow, **what permissions** the token needs, and **where credentials come from**. Get those wrong and you have a fast pipeline that leaks secrets or a secure one nobody can trigger. Everything after that — checkout, install, test, build — is just steps.
12
12
 
13
- This skill owns the workflow layer: the `.github/workflows/*.yml` files, their triggers, jobs, matrix, caching, secret/OIDC handling, environments, and deploy gates. It does not own the image you build, the branching model, or the release decision (see the boundaries below).
13
+ This skill owns the workflow layer — the `.github/workflows/*.yml` files, their triggers, jobs, matrix, caching, secret/OIDC handling, environments and deploy gates. Route the rest out:
14
14
 
15
- ## Use this when
16
-
17
- - Writing or fixing a `ci.yml` / `deploy.yml` / `release.yml`.
18
- - Adding lint/test/build jobs on push or pull_request.
19
- - Speeding up CI with dependency caching.
20
- - Running a build across an OS x language-version matrix.
21
- - Wiring deploys: environments, approval gates, OIDC to a cloud, secrets.
22
- - Reusable workflows (`workflow_call`) and composite actions to kill copy-paste.
23
- - Killing redundant runs with `concurrency`; SHA-pinning actions for supply-chain safety.
24
-
25
- ## Not this when
26
-
27
- - Authoring the `Dockerfile` or deciding the image build strategy → docker. The workflow may *call* `docker build`; designing the image is not this skill.
28
- - Branching model, PR hygiene, merge vs rebase, commit conventions → git-workflow.
29
- - Release readiness checklist, changelog, the shipping decision → `../ship/SKILL.md`.
30
- - Blue/green, canary, rollback *theory* → `../deployment/SKILL.md`. Actions triggers the deploy; the strategy is deployment's.
31
- - Choosing the host and its deploy primitives → `../vercel/SKILL.md` / `../aws-essentials/SKILL.md` / the host skill. Actions *triggers* the deploy; the host owns the target.
32
- - Triaging SAST/CVE findings or threat-modeling → `../secure-coding/SKILL.md`. This skill runs a scanner *as a job*; it does not interpret the report.
15
+ | Not this skill | Goes to | Because |
16
+ | --- | --- | --- |
17
+ | The `Dockerfile`, image build strategy | `../docker/SKILL.md` | The workflow may *call* `docker build`; designing the image is not this skill. |
18
+ | Branching model, PR hygiene, merge vs rebase, commit conventions | `../git-workflow/SKILL.md` | That is the source-control model, not the CI config layer. |
19
+ | Release readiness checklist, changelog, the shipping decision | `../ship/SKILL.md` | Whether to release is a decision; this skill only automates the mechanics. |
20
+ | Blue/green, canary, rollback *theory* | `../deployment/SKILL.md` | Actions triggers the deploy; the strategy is deployment's. |
21
+ | Choosing the host and its deploy primitives | `../vercel/SKILL.md`, `../aws-essentials/SKILL.md` | Actions *triggers* the deploy; the host owns the target. |
22
+ | Triaging SAST/CVE findings, threat modeling | `../secure-coding/SKILL.md` | This skill runs a scanner *as a job*; it does not interpret the report. |
33
23
 
34
24
  ## Decide the trigger first
35
25
 
@@ -74,16 +64,15 @@ jobs:
74
64
  with:
75
65
  node-version: 22
76
66
  cache: npm # built-in lockfile-keyed cache
77
- - run: npm ci # ci, not install — respects the lockfile
67
+ - run: npm ci # not install — fails on a stale lockfile, reproducible
78
68
  - run: npm run lint
79
69
  - run: npm test
80
70
  ```
81
71
 
82
- Rules baked into that file, each with its why:
83
- - `permissions: contents: read` at the top — **default token permissions may be write**; declare read-only and widen per job. A leaked write token can push tags or publish packages.
84
- - `concurrency` + `cancel-in-progress: true` — without it, every push to an open PR leaves the old run finishing and billing. One group per ref keeps at most one running + one pending.
85
- - `npm ci` not `npm install` — `ci` fails on a stale lockfile and is reproducible.
86
- - `actions/checkout@v6`, `setup-node@v6` — current majors (checkout v6.0.2, setup-node v6.4.0). Old majors run on Node 20, removed from runners in **September 2026**; JS actions are forced onto **Node 24** by default since June 2026. Upgrade to silence deprecation warnings and stay supported.
72
+ Why those three lines are not optional:
73
+ - `permissions: contents: read` at the top — **default token permissions may be write**, and a leaked write token can push tags or publish packages. Widen per job and only to what that job needs (`packages: write` to publish, `id-token: write` for OIDC), never at the top.
74
+ - `concurrency` + `cancel-in-progress: true` — without it every push to an open PR leaves the old run finishing and billing. One group per ref keeps at most one running + one pending.
75
+ - `actions/checkout@v6`, `setup-node@v6` are the current majors (checkout v6.0.2, setup-node v6.4.0). Old majors run on Node 20, removed from runners in **September 2026**; JS actions are forced onto **Node 24** by default since June 2026.
87
76
 
88
77
  ## Caching
89
78
 
@@ -183,7 +172,6 @@ Per-cloud trust setup (AWS role, GCP Workload Identity Federation, Azure federat
183
172
  ```
184
173
 
185
174
  First-party `actions/*` and `github/*` may stay on a major tag (GitHub controls them), but pinning everything is the stronger posture.
186
- - **Keep `GITHUB_TOKEN` read-only by default**, widen per job. Set `permissions: contents: read` at the top, then grant exactly what a job needs (`packages: write` to publish, `id-token: write` for OIDC).
187
175
  - **`pull_request_target` + checking out the PR head = remote code execution with your secrets.** That trigger runs in the *base* repo's trusted context. If you then `checkout` `github.event.pull_request.head.sha`, you execute a fork's code with full secret access. Never combine them.
188
176
 
189
177
  ## Reuse: workflow vs composite action
@@ -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: 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