@ericrisco/rsc 0.1.52 → 0.1.53
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 +9 -9
- package/package.json +1 -1
- package/skills/gamedev-shaders/SKILL.md +23 -43
- package/skills/gamedev-shaders/evals/cases.yaml +2 -2
- package/skills/gcp-essentials/SKILL.md +16 -19
- package/skills/hetzner/SKILL.md +18 -36
- package/skills/knowledge-ops/SKILL.md +14 -17
- package/skills/medium-publishing/SKILL.md +5 -13
- package/skills/n8n/SKILL.md +37 -65
- package/skills/notion-connector/SKILL.md +13 -26
- package/skills/planetscale/SKILL.md +18 -43
- package/skills/planetscale/references/no-foreign-keys.md +2 -2
package/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.1.
|
|
2
|
+
"version": "0.1.53",
|
|
3
3
|
"counts": {
|
|
4
4
|
"skills": 258
|
|
5
5
|
},
|
|
@@ -1950,7 +1950,7 @@
|
|
|
1950
1950
|
},
|
|
1951
1951
|
{
|
|
1952
1952
|
"id": "gamedev-shaders",
|
|
1953
|
-
"description": "Use when
|
|
1953
|
+
"description": "Use when authoring or debugging a shader, material, VFX, or full-screen post-process in a game engine — Godot 4.x `.gdshader`, Unity 6 URP/HDRP, Unreal 5.x Materials, effect recipes, shader performance. NOT gameplay or engine-API code (that is `godot`/`unity`/`unreal`), NOT physics (`gamedev-physics`), NOT build variant stripping (`gamedev-shipping`).",
|
|
1954
1954
|
"tags": [
|
|
1955
1955
|
"shaders",
|
|
1956
1956
|
"vfx",
|
|
@@ -1995,7 +1995,7 @@
|
|
|
1995
1995
|
},
|
|
1996
1996
|
{
|
|
1997
1997
|
"id": "gcp-essentials",
|
|
1998
|
-
"description": "Use when running a small product on
|
|
1998
|
+
"description": "Use when running a small product on core Google Cloud via the gcloud CLI: a project, Cloud Run deploys, a locked-down Cloud Storage bucket, managed Cloud SQL, and least-privilege IAM wiring them together. NOT AWS (that is `aws-essentials`), NOT the CI pipeline that ships the image (that is `deployment`), NOT Postgres schema/query tuning (that is `postgresdb`).",
|
|
1999
1999
|
"tags": [
|
|
2000
2000
|
"gcp",
|
|
2001
2001
|
"cloud-run",
|
|
@@ -2192,7 +2192,7 @@
|
|
|
2192
2192
|
},
|
|
2193
2193
|
{
|
|
2194
2194
|
"id": "hetzner",
|
|
2195
|
-
"description": "Use when provisioning or hardening a Hetzner Cloud VPS
|
|
2195
|
+
"description": "Use when provisioning or hardening a Hetzner Cloud VPS: picking the plan/location (CX/CPX/CAX/CCX), bringing it up reproducibly with hcloud + cloud-init, locking down SSH, and wiring the Cloud Firewall to hand off a Docker-ready host. NOT app deploys on Coolify (that is `coolify`), NOT Dockerfiles (that is `docker`), NOT another provider (that is `digitalocean`).",
|
|
2196
2196
|
"tags": [
|
|
2197
2197
|
"hetzner",
|
|
2198
2198
|
"vps",
|
|
@@ -2439,7 +2439,7 @@
|
|
|
2439
2439
|
},
|
|
2440
2440
|
{
|
|
2441
2441
|
"id": "knowledge-ops",
|
|
2442
|
-
"description": "Use when an already-running 02-DOCS/ wiki needs
|
|
2442
|
+
"description": "Use when an already-running 02-DOCS/ wiki needs gardening judgment — what is worth capturing (default: nothing), where a loose note belongs, whether to split a bloated article or merge near-duplicates, how to link orphans back in, and what retires to _archive (never delete). NOT building or sweeping the wiki engine itself (that is `harness`).",
|
|
2443
2443
|
"tags": [
|
|
2444
2444
|
"knowledge-ops",
|
|
2445
2445
|
"wiki",
|
|
@@ -2827,7 +2827,7 @@
|
|
|
2827
2827
|
},
|
|
2828
2828
|
{
|
|
2829
2829
|
"id": "medium-publishing",
|
|
2830
|
-
"description": "Use when
|
|
2830
|
+
"description": "Use when a finished article has to land on Medium correctly — profile vs publication, cross-posting under a canonical link so your own site keeps the SEO credit, import-tool failures, the 5-tag cap, pseudo-Markdown gotchas. NOT writing or headlining the piece (that is `medium-writing`), NOT cadence or earnings (that is `medium-strategy`).",
|
|
2831
2831
|
"tags": [
|
|
2832
2832
|
"medium",
|
|
2833
2833
|
"publishing",
|
|
@@ -2992,7 +2992,7 @@
|
|
|
2992
2992
|
},
|
|
2993
2993
|
{
|
|
2994
2994
|
"id": "n8n",
|
|
2995
|
-
"description": "Use when operating a live n8n instance programmatically —
|
|
2995
|
+
"description": "Use when operating a live n8n instance programmatically — its REST API (`{host}/api/v1`, `X-N8N-API-KEY`) or the n8n-mcp server — to create, validate, test, activate, update, delete workflows and read executions on self-host or n8n.cloud. NOT designing the flow or its importable JSON (that is `automation-flows`), NOT another platform (`make`, `zapier`).",
|
|
2996
2996
|
"tags": [
|
|
2997
2997
|
"n8n",
|
|
2998
2998
|
"automation",
|
|
@@ -3177,7 +3177,7 @@
|
|
|
3177
3177
|
},
|
|
3178
3178
|
{
|
|
3179
3179
|
"id": "notion-connector",
|
|
3180
|
-
"description": "Use when wiring
|
|
3180
|
+
"description": "Use when wiring server code or a cron job to Notion as an ops backend over its HTTP API: pushing or mirroring database rows, two-way sync without duplicates, page blocks, or an integration broken by the 2025-09-03 data-source split. NOT generic REST wiring (that is `api-connector-builder`), NOT inbound Notion webhook events (that is `webhooks`).",
|
|
3181
3181
|
"tags": [
|
|
3182
3182
|
"notion",
|
|
3183
3183
|
"ops-backend",
|
|
@@ -3406,7 +3406,7 @@
|
|
|
3406
3406
|
},
|
|
3407
3407
|
{
|
|
3408
3408
|
"id": "planetscale",
|
|
3409
|
-
"description": "Use when operating PlanetScale serverless MySQL
|
|
3409
|
+
"description": "Use when operating PlanetScale (Vitess serverless MySQL) — branches and the `pscale` CLI, schema changes through deploy requests (Online DDL cutover, ~30-min revert window), tables without foreign keys, or the edge HTTP driver. NOT MySQL engine work like EXPLAIN or index choice (that is `mysql`), NOT generic migration theory (that is `db-migrations`).",
|
|
3410
3410
|
"tags": [
|
|
3411
3411
|
"planetscale",
|
|
3412
3412
|
"vitess",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gamedev-shaders
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when authoring or debugging a shader, material, VFX, or full-screen post-process in a game engine — Godot 4.x `.gdshader`, Unity 6 URP/HDRP, Unreal 5.x Materials, effect recipes, shader performance. NOT gameplay or engine-API code (that is `godot`/`unity`/`unreal`), NOT physics (`gamedev-physics`), NOT build variant stripping (`gamedev-shipping`)."
|
|
4
4
|
tags: [shaders, vfx, materials, post-processing, shadergraph]
|
|
5
5
|
recommends: [godot, unity, unreal, gamedev-shipping]
|
|
6
6
|
profiles: [full]
|
|
@@ -11,8 +11,7 @@ origin: risco
|
|
|
11
11
|
|
|
12
12
|
Author shaders, materials, and full-screen effects across Godot, Unity, and Unreal. One
|
|
13
13
|
mental model — the GPU pipeline — mapped onto each engine's authoring surface, plus recipes
|
|
14
|
-
for the effects people actually ask for.
|
|
15
|
-
building a VFX/post-process effect, or "how do I make X look like Y".
|
|
14
|
+
for the effects people actually ask for.
|
|
16
15
|
|
|
17
16
|
## Version contract — read first
|
|
18
17
|
|
|
@@ -28,22 +27,6 @@ symbol is current, say so rather than guess.
|
|
|
28
27
|
`shader_type` tokens in Godot 4 are exact: `spatial`, `canvas_item` (underscore), `particles`
|
|
29
28
|
(plural), `sky`, `fog`.
|
|
30
29
|
|
|
31
|
-
## When to use / When NOT to use
|
|
32
|
-
|
|
33
|
-
**Use when:** writing or debugging a `.gdshader`/`ShaderMaterial`, a `.shader`/Shader Graph, or
|
|
34
|
-
a UE Material; building a VFX look (dissolve, rim, toon, water, shield, hologram, trails);
|
|
35
|
-
authoring post-processing / screen-space effects; a shader is slow, flickers, or looks wrong;
|
|
36
|
-
choosing per-vertex vs per-pixel; converting an effect between engines.
|
|
37
|
-
|
|
38
|
-
**When NOT to use (delegate):**
|
|
39
|
-
|
|
40
|
-
- Gameplay logic, nodes/components, input, engine APIs, scene setup → [`godot`](../godot/SKILL.md) /
|
|
41
|
-
[`unity`](../unity/SKILL.md) / [`unreal`](../unreal/SKILL.md). This skill owns the *shading*, not the C#/GDScript/Blueprint around it.
|
|
42
|
-
- Physics simulation, collisions, rigid bodies, character controllers → [`gamedev-physics`](../gamedev-physics/SKILL.md).
|
|
43
|
-
(A shader that *fakes* refraction is here; simulating fluid dynamics is not.)
|
|
44
|
-
- Shipping, platform export, shader-variant stripping in the build pipeline → [`gamedev-shipping`](../gamedev-shipping/SKILL.md)
|
|
45
|
-
(this skill keeps the per-shader performance work).
|
|
46
|
-
|
|
47
30
|
## Shader fundamentals (the pipeline)
|
|
48
31
|
|
|
49
32
|
Every engine compiles your material into the same GPU stages. Two you write:
|
|
@@ -131,10 +114,10 @@ for high-end):
|
|
|
131
114
|
blocks; the program goes in an `HLSLPROGRAM … ENDHLSL` block that `#include`s URP's `Core.hlsl`
|
|
132
115
|
/ `Lighting.hlsl`. Use for full control, custom lighting, or compute-driven effects.
|
|
133
116
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
117
|
+
Surface shaders are not an option under URP/HDRP (see the Version contract) — a lit look is an
|
|
118
|
+
HLSL pass or a Shader Graph. Set parameters at runtime through a `MaterialPropertyBlock` or
|
|
119
|
+
`Material.SetFloat/SetColor/SetTexture`. Full URP unlit + lit HLSL pass and a Shader Graph
|
|
120
|
+
mapping → `references/unity-and-unreal-shaders.md`.
|
|
138
121
|
|
|
139
122
|
### Unreal 5.x
|
|
140
123
|
|
|
@@ -216,24 +199,27 @@ per engine → `references/effect-recipes.md`.
|
|
|
216
199
|
- **Mobile / tile GPUs**: bandwidth-bound — keep render targets small, avoid mid-pass framebuffer
|
|
217
200
|
reads, and note that `discard` and large full-screen passes break tile hidden-surface removal.
|
|
218
201
|
|
|
219
|
-
##
|
|
202
|
+
## Anti-patterns
|
|
220
203
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
204
|
+
| Anti-pattern | Do instead |
|
|
205
|
+
| --- | --- |
|
|
206
|
+
| Porting a tutorial verbatim from Godot 3, Built-in RP, or pre-5.0 UE | Translate it through the Version contract table first — retired symbols still compile in old guides, not in your project. |
|
|
207
|
+
| Reading a texture or writing a color without minding linear vs sRGB | Author color uniforms as `source_color` (Godot) / sRGB-marked properties and check the space at every read and output — the #1 "looks washed out / too dark" bug. |
|
|
208
|
+
| Using interpolated normals raw, or a normal map straight from the sample | Re-normalize per pixel; unpack with `×2−1` and mind tangent handedness. |
|
|
209
|
+
| Writing the shader before choosing the target surface | Pick `shader_type` / render pipeline / material domain first (2D vs 3D, URP vs HDRP, Surface vs Post Process) — it decides which built-ins and blend modes exist. |
|
|
210
|
+
| Fresnel, normalization, or lighting math in the vertex stage | Only linearly-interpolating work goes per-vertex; exact math stays per-pixel. |
|
|
211
|
+
| `discard`/`clip` as a cheap "make it invisible" | Cull it or scale to zero — `discard` disables early-Z and breaks tile hidden-surface removal on mobile. |
|
|
212
|
+
| Stacking additive/translucent layers until the look works | Count the overdraw: each layer re-shades the same pixels. Prefer opaque, minimize overlap, keep particle fill low. |
|
|
213
|
+
| Full-screen effects via `OnRenderImage`/`Graphics.Blit`, or `SceneTexture` outside the Post Process domain | Use the engine's supported path — URP Renderer Feature / Fullscreen Shader Graph, UE Post Process material, Godot `ColorRect` + `hint_screen_texture` or `CompositorEffect`. |
|
|
230
214
|
|
|
231
215
|
## Related skills
|
|
232
216
|
|
|
233
|
-
- [`godot`](../godot/SKILL.md) / [`unity`](../unity/SKILL.md) / [`unreal`](../unreal/SKILL.md) —
|
|
234
|
-
|
|
235
|
-
- [`gamedev-physics`](../gamedev-physics/SKILL.md) — simulation, collision, rigid bodies
|
|
236
|
-
|
|
217
|
+
- [`godot`](../godot/SKILL.md) / [`unity`](../unity/SKILL.md) / [`unreal`](../unreal/SKILL.md) — gameplay
|
|
218
|
+
code, nodes/components, input, scene wiring; this skill owns the *shading*, not the C#/GDScript/Blueprint around it.
|
|
219
|
+
- [`gamedev-physics`](../gamedev-physics/SKILL.md) — simulation, collision, rigid bodies, character
|
|
220
|
+
controllers (a shader that *fakes* refraction is here; simulating fluid dynamics is not).
|
|
221
|
+
- [`gamedev-shipping`](../gamedev-shipping/SKILL.md) — platform export and shader-variant stripping in
|
|
222
|
+
the build (this skill keeps the per-shader performance work).
|
|
237
223
|
|
|
238
224
|
## Checklist
|
|
239
225
|
|
|
@@ -244,9 +230,3 @@ per engine → `references/effect-recipes.md`.
|
|
|
244
230
|
- [ ] Uniforms/parameters exposed and driven from code or an animation track — not hard-coded.
|
|
245
231
|
- [ ] Performance sanity: overdraw, sample count, and branching considered; mobile precision set if targeted.
|
|
246
232
|
- [ ] Post-process uses the engine's supported full-screen path (not a retired Built-in-RP mechanism).
|
|
247
|
-
|
|
248
|
-
## References
|
|
249
|
-
|
|
250
|
-
- `references/godot-shading-language.md` — shader types, built-ins per type, render_modes, `varying`, screen/depth reads, ShaderMaterial from code.
|
|
251
|
-
- `references/unity-and-unreal-shaders.md` — Unity URP HLSL pass + Shader Graph mapping; Unreal domains, Custom node HLSL, Material Instances.
|
|
252
|
-
- `references/effect-recipes.md` — dissolve, rim/outline, toon/cel, water/flow, force field, hologram — full code per engine.
|
|
@@ -4,13 +4,13 @@ should_trigger:
|
|
|
4
4
|
- prompt: "Write me a dissolve shader in Godot 4 that burns an object away from bottom to top with a glowing orange edge."
|
|
5
5
|
why: "Dissolve is a named recipe and the core use case; Godot 4 .gdshader authoring is owned here."
|
|
6
6
|
- prompt: "How do I make a rim light / fresnel glow on a 3D character in Unity URP?"
|
|
7
|
-
why: "Rim/fresnel is a named recipe; 'how do I make X effect' is
|
|
7
|
+
why: "Rim/fresnel is a named recipe; 'how do I make X effect' is the core shape of a shader request; Unity shader authoring is per-engine mapped here."
|
|
8
8
|
- prompt: "My translucent particle shader tanks the framerate on mobile. How do I fix the overdraw?"
|
|
9
9
|
why: "Shader performance — overdraw, transparency, mobile — is a dedicated section; symptom-only trigger routes here, not to a generic profiler."
|
|
10
10
|
- prompt: "Set up a full-screen post-process effect in Unreal that reads scene depth and draws outlines."
|
|
11
11
|
why: "Post-processing / full-screen effects per engine is a core section; Unreal Post Process material + SceneTexture is covered."
|
|
12
12
|
- prompt: "Cómo hago un shader de agua con refracción y espuma en los bordes."
|
|
13
|
-
why: "Spanish water/flow recipe request;
|
|
13
|
+
why: "Spanish water/flow recipe request; water/flow is a named recipe and matching is by meaning, not by language."
|
|
14
14
|
- prompt: "Convert this toon/cel shading effect from my Godot project to a Unity Shader Graph."
|
|
15
15
|
why: "Toon/cel is a named recipe and cross-engine conversion is an explicit use case; the skill carries a Godot↔Unity↔Unreal map."
|
|
16
16
|
- prompt: "What coordinate space are NORMAL and VIEW in inside a Godot spatial fragment shader, and why does my world-space fresnel look wrong?"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gcp-essentials
|
|
3
|
-
description: "Use when running a small product on
|
|
3
|
+
description: "Use when running a small product on core Google Cloud via the gcloud CLI: a project, Cloud Run deploys, a locked-down Cloud Storage bucket, managed Cloud SQL, and least-privilege IAM wiring them together. NOT AWS (that is `aws-essentials`), NOT the CI pipeline that ships the image (that is `deployment`), NOT Postgres schema/query tuning (that is `postgresdb`)."
|
|
4
4
|
tags: [gcp, cloud-run, cloud-sql, cloud-storage, iam, gcloud, serverless, devops]
|
|
5
5
|
recommends: [aws-essentials, docker, github-actions, secure-coding, postgresdb, deployment, monitoring, backups]
|
|
6
6
|
origin: risco
|
|
@@ -20,12 +20,14 @@ Four primitives carry most products, plus the project/billing scaffold under the
|
|
|
20
20
|
- **Cloud Storage** — object storage (buckets).
|
|
21
21
|
- **Cloud SQL** — managed Postgres/MySQL.
|
|
22
22
|
|
|
23
|
-
Out of scope, route elsewhere: AWS -> `aws-essentials
|
|
24
|
-
|
|
23
|
+
Out of scope, route elsewhere: AWS -> [`../aws-essentials/SKILL.md`](../aws-essentials/SKILL.md).
|
|
24
|
+
Building/shipping the image itself -> [`../docker/SKILL.md`](../docker/SKILL.md)
|
|
25
|
+
/ [`../github-actions/SKILL.md`](../github-actions/SKILL.md) / [`../deployment/SKILL.md`](../deployment/SKILL.md).
|
|
25
26
|
Postgres schema/index/query tuning -> [`../postgresdb/SKILL.md`](../postgresdb/SKILL.md).
|
|
26
27
|
App-level injection/secret-handling review -> [`../secure-coding/SKILL.md`](../secure-coding/SKILL.md).
|
|
27
|
-
Logging/alerting/SLOs as a practice -> `monitoring
|
|
28
|
-
|
|
28
|
+
Logging/alerting/SLOs as a practice -> [`../monitoring/SKILL.md`](../monitoring/SKILL.md).
|
|
29
|
+
Backup strategy as a discipline -> [`../backups/SKILL.md`](../backups/SKILL.md).
|
|
30
|
+
One-click PaaS where you never touch IAM/VPC -> [`../vercel/SKILL.md`](../vercel/SKILL.md)
|
|
29
31
|
/ [`../railway/SKILL.md`](../railway/SKILL.md) / [`../render/SKILL.md`](../render/SKILL.md)
|
|
30
32
|
/ [`../fly-io/SKILL.md`](../fly-io/SKILL.md).
|
|
31
33
|
|
|
@@ -96,8 +98,8 @@ Two hard rules, each with teeth:
|
|
|
96
98
|
Identity Federation for external/CI auth (GitHub Actions). If `... keys create` is
|
|
97
99
|
in your runbook, the runbook is wrong.
|
|
98
100
|
|
|
99
|
-
WIF for keyless CI, SA impersonation, IAM Recommender and
|
|
100
|
-
[`references/iam-and-auth.md`](references/iam-and-auth.md).
|
|
101
|
+
The predefined-role catalog, WIF for keyless CI, SA impersonation, IAM Recommender and
|
|
102
|
+
Conditions live in [`references/iam-and-auth.md`](references/iam-and-auth.md).
|
|
101
103
|
|
|
102
104
|
## 2. Cloud Run
|
|
103
105
|
|
|
@@ -233,8 +235,9 @@ gcloud run deploy api --region=europe-west1 \
|
|
|
233
235
|
```
|
|
234
236
|
|
|
235
237
|
The Cloud SQL **Auth Proxy** (short-lived certs, TLS 1.3) is for connecting from
|
|
236
|
-
*outside* — local dev or a non-serverless host — not for Cloud Run.
|
|
237
|
-
|
|
238
|
+
*outside* — local dev or a non-serverless host — not for Cloud Run. Direct VPC egress vs
|
|
239
|
+
legacy connectors, private IP / PSC, proxy invocation and pooling are in
|
|
240
|
+
[`references/networking-and-sql.md`](references/networking-and-sql.md).
|
|
238
241
|
|
|
239
242
|
## 5. Wire it together
|
|
240
243
|
|
|
@@ -267,6 +270,10 @@ Note the scoping: `cloudsql.client` is project-wide (the role needs it), but the
|
|
|
267
270
|
storage and secret grants are bound to the *specific* bucket and secret, not the
|
|
268
271
|
project. Grant narrow.
|
|
269
272
|
|
|
273
|
+
Copy-paste runbooks for each piece — image build and push, private container deploy,
|
|
274
|
+
attach SQL, mount a secret, full teardown — are in
|
|
275
|
+
[`references/deploy-recipes.md`](references/deploy-recipes.md).
|
|
276
|
+
|
|
270
277
|
## 6. Cost & teardown
|
|
271
278
|
|
|
272
279
|
- Cloud Run scales to zero by default — an idle service costs ~nothing. Keep
|
|
@@ -315,13 +322,3 @@ bash scripts/verify.sh path/to/dir/ # recurse a directory
|
|
|
315
322
|
|
|
316
323
|
It prints `PASS`/`FAIL` per check and exits nonzero on any FAIL. An empty or
|
|
317
324
|
clean target passes (exit 0).
|
|
318
|
-
|
|
319
|
-
## References
|
|
320
|
-
|
|
321
|
-
- [`references/iam-and-auth.md`](references/iam-and-auth.md) — predefined-role catalog,
|
|
322
|
-
Workload Identity Federation for GitHub Actions, SA impersonation, IAM Recommender,
|
|
323
|
-
Conditions.
|
|
324
|
-
- [`references/networking-and-sql.md`](references/networking-and-sql.md) — Direct VPC
|
|
325
|
-
egress vs legacy connectors, Cloud SQL private IP / PSC, Auth Proxy, pooling.
|
|
326
|
-
- [`references/deploy-recipes.md`](references/deploy-recipes.md) — copy-paste runbooks:
|
|
327
|
-
container deploy, attach SQL, mount a secret, budget alert, full teardown.
|
package/skills/hetzner/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hetzner
|
|
3
|
-
description: "Use when provisioning or hardening a Hetzner Cloud VPS
|
|
3
|
+
description: "Use when provisioning or hardening a Hetzner Cloud VPS: picking the plan/location (CX/CPX/CAX/CCX), bringing it up reproducibly with hcloud + cloud-init, locking down SSH, and wiring the Cloud Firewall to hand off a Docker-ready host. NOT app deploys on Coolify (that is `coolify`), NOT Dockerfiles (that is `docker`), NOT another provider (that is `digitalocean`)."
|
|
4
4
|
tags: [hetzner, vps, cloud-firewall, hcloud, ssh-hardening, cloud-init, self-hosting]
|
|
5
5
|
recommends: [coolify, docker, secure-coding, domains-dns, backups, monitoring]
|
|
6
6
|
origin: risco
|
|
@@ -14,17 +14,8 @@ include 20 TB of egress. The risk is that "cheap" becomes "unhardened and
|
|
|
14
14
|
unmonitored" — a root-SSH box on a public IPv4 with password auth on. Your job
|
|
15
15
|
is to make the cheap box **safe** and **reproducible**: every server comes up
|
|
16
16
|
from a committed cloud-init file and a Cloud Firewall ruleset, never from
|
|
17
|
-
click-ops in the console.
|
|
18
|
-
|
|
19
|
-
Operating posture:
|
|
20
|
-
|
|
21
|
-
- **Reproducible by default.** A box you can't recreate from a file isn't a box,
|
|
22
|
-
it's a pet. Bake the non-root user, SSH key, and sshd hardening into first
|
|
23
|
-
boot via cloud-init — not into a post-login checklist you'll forget.
|
|
24
|
-
- **Two firewalls, edge first.** The Hetzner Cloud Firewall stops packets before
|
|
25
|
-
they reach the VM; host `ufw` is defense-in-depth. You need both.
|
|
26
|
-
- **Honest about the trade-off.** No managed DB, no uptime SLA, phone support
|
|
27
|
-
only for dedicated-server customers. Name it; don't pretend it's AWS.
|
|
17
|
+
click-ops in the console. A box you can't recreate from a file isn't a box, it's
|
|
18
|
+
a pet.
|
|
28
19
|
|
|
29
20
|
## Decide before you create
|
|
30
21
|
|
|
@@ -139,8 +130,8 @@ hcloud firewall add-rule app-edge --direction in --protocol tcp --port 22 --s
|
|
|
139
130
|
|
|
140
131
|
## SSH hardening rules
|
|
141
132
|
|
|
142
|
-
- **Key-only auth.** `PasswordAuthentication no`. A
|
|
143
|
-
an ed25519 key is not.
|
|
133
|
+
- **Key-only auth.** `PasswordAuthentication no`, `PubkeyAuthentication yes`. A
|
|
134
|
+
password is brute-forceable; an ed25519 key is not.
|
|
144
135
|
- **No root login.** `PermitRootLogin no` + a sudo user. Root over SSH is the
|
|
145
136
|
single most-targeted login on the internet.
|
|
146
137
|
- **fail2ban on.** Bans IPs after repeated failures — cheap insurance for the
|
|
@@ -149,16 +140,6 @@ hcloud firewall add-rule app-edge --direction in --protocol tcp --port 22 --s
|
|
|
149
140
|
harden anything. Do it if you like clean logs, but never *instead* of key-only
|
|
150
141
|
+ a firewall.
|
|
151
142
|
|
|
152
|
-
Bad → Good:
|
|
153
|
-
|
|
154
|
-
```diff
|
|
155
|
-
- PermitRootLogin yes
|
|
156
|
-
- PasswordAuthentication yes
|
|
157
|
-
+ PermitRootLogin no
|
|
158
|
-
+ PasswordAuthentication no
|
|
159
|
-
+ PubkeyAuthentication yes
|
|
160
|
-
```
|
|
161
|
-
|
|
162
143
|
## Hand off to Docker / Coolify
|
|
163
144
|
|
|
164
145
|
"Host ready" means all of the following are true:
|
|
@@ -169,28 +150,29 @@ Bad → Good:
|
|
|
169
150
|
- [ ] `ufw status` enabled with the same allowlist.
|
|
170
151
|
- [ ] `unattended-upgrades` and `fail2ban` running.
|
|
171
152
|
|
|
172
|
-
Then route the install/deploy:
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
image hardening. This skill stops at a clean, hardened host.
|
|
153
|
+
This skill stops at a clean, hardened host. Then route the install/deploy:
|
|
154
|
+
[`coolify`](../coolify/SKILL.md) for the Coolify install + app deploy flow,
|
|
155
|
+
[`docker`](../docker/SKILL.md) for Dockerfiles, compose, and image hardening.
|
|
176
156
|
|
|
177
157
|
## Day-2
|
|
178
158
|
|
|
179
159
|
- **Snapshot ≠ backup.** A snapshot is a one-off manual image you can boot from;
|
|
180
160
|
the **Backups** add-on is automated, rotating, ~20% of the server price. A
|
|
181
|
-
snapshot you took once in March is not a backup strategy — for that, see
|
|
182
|
-
`backups`
|
|
161
|
+
snapshot you took once in March is not a backup strategy — for that, see
|
|
162
|
+
[`backups`](../backups/SKILL.md).
|
|
183
163
|
- **Resize grows, never shrinks.** You can scale the disk up; you cannot scale it
|
|
184
164
|
back down. Size conservatively or you're stuck paying for it.
|
|
185
165
|
- **Volumes** for data you want to outlive/detach from the server. Keep databases
|
|
186
166
|
and uploads on a volume so a server rebuild doesn't take the data with it.
|
|
187
167
|
- **Reverse DNS** must match for outbound mail to be accepted — set the PTR in the
|
|
188
|
-
console/`hcloud` if the box sends email. Forward DNS records belong to
|
|
189
|
-
`domains-dns`
|
|
190
|
-
- **No SLA, no managed DB.** There's no uptime guarantee
|
|
191
|
-
product
|
|
192
|
-
|
|
193
|
-
|
|
168
|
+
console/`hcloud` if the box sends email. Forward DNS records belong to
|
|
169
|
+
[`domains-dns`](../domains-dns/SKILL.md).
|
|
170
|
+
- **No SLA, no managed DB.** There's no uptime guarantee, no managed-database
|
|
171
|
+
product, and phone support only for dedicated-server customers — you run
|
|
172
|
+
Postgres yourself, you monitor it yourself. For monitoring and alerting, see
|
|
173
|
+
[`monitoring`](../monitoring/SKILL.md); treat the box as something you must
|
|
174
|
+
watch, not something Hetzner watches for you. Name the trade-off to the user;
|
|
175
|
+
don't pretend it's AWS.
|
|
194
176
|
|
|
195
177
|
## Anti-patterns
|
|
196
178
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: knowledge-ops
|
|
3
|
-
description: "Use when an already-running 02-DOCS/ wiki needs
|
|
3
|
+
description: "Use when an already-running 02-DOCS/ wiki needs gardening judgment — what is worth capturing (default: nothing), where a loose note belongs, whether to split a bloated article or merge near-duplicates, how to link orphans back in, and what retires to _archive (never delete). NOT building or sweeping the wiki engine itself (that is `harness`)."
|
|
4
4
|
tags: [knowledge-ops, wiki, 02-docs, knowledge-base, curation, cross-linking, pruning, knowledge-meta]
|
|
5
5
|
recommends: [harness, decision-records, meeting-notes, sop-builder, research-ops, codebase-onboarding]
|
|
6
6
|
origin: risco
|
|
@@ -8,7 +8,7 @@ origin: risco
|
|
|
8
8
|
|
|
9
9
|
# Knowledge Ops — Garden the 02-DOCS Wiki
|
|
10
10
|
|
|
11
|
-
*The engine is already running. `harness` built the `02-DOCS/` wiki and owns its automation — the inbox sweep, deterministic lint, scoring, gap detection, the self-improve loop
|
|
11
|
+
*The engine is already running. `harness` built the `02-DOCS/` wiki and owns its automation — the inbox sweep, deterministic lint, scoring, gap detection, the self-improve loop — and changing that machinery or filling the wiki in bulk stays with it. Yours are the four judgments automation deliberately leaves to a human: what is worth capturing, how it should be shaped, how it connects, and what should retire. You are the gardener, not the machinery.*
|
|
12
12
|
|
|
13
13
|
## Before you touch anything
|
|
14
14
|
|
|
@@ -29,7 +29,7 @@ Every gardening request is one of four operations. Identify which before you act
|
|
|
29
29
|
| **Link** | Pages are unreachable or under-connected | `scores.json` orphan_penalty (=5), low inbound count | `## See Also` in articles, `index.md` |
|
|
30
30
|
| **Prune** | Answers are stale, articles superseded, conflicts unresolved, gaps bloated | freshness, conflict annotations, old `[FILLED]` gaps | `_archive/`, `log.md`, `gaps.md` |
|
|
31
31
|
|
|
32
|
-
Whichever you do, record a line in `wiki/log.md
|
|
32
|
+
Whichever you do, record a line in `wiki/log.md` under the reserved-file rule in **Safety rails** below. The exact entry shapes per operation live in `references/gardening-playbook.md`.
|
|
33
33
|
|
|
34
34
|
## Capture — the bar is high
|
|
35
35
|
|
|
@@ -44,7 +44,7 @@ Walk the altitude ladder, lowest rung first; stop at the first that fits:
|
|
|
44
44
|
|
|
45
45
|
Worked examples for each rung are in `references/gardening-playbook.md`.
|
|
46
46
|
|
|
47
|
-
**Topic choice.** Reuse an existing topic before inventing one, and keep `wiki/` exactly **one level of subdirs** deep (the protocol's rule).
|
|
47
|
+
**Topic choice.** Reuse an existing topic before inventing one, and keep `wiki/` exactly **one level of subdirs** deep (the protocol's rule).
|
|
48
48
|
|
|
49
49
|
- Bad: `wiki/payments/stripe/webhooks/retries.md` (four levels deep).
|
|
50
50
|
- Good: `wiki/payments/stripe-webhook-retries.md` (existing `payments/` topic, one level).
|
|
@@ -81,20 +81,19 @@ Every article earns **≥1 inbound link** or is a conscious leaf you can justify
|
|
|
81
81
|
|
|
82
82
|
- **Conflicts:** you **flag** contradictions and the **human arbitrates**. Once they choose a winner, you may apply the resolution and annotate the loser — but you never auto-pick. Why: silently choosing a side is data corruption.
|
|
83
83
|
- **Stale answers:** mark a page or archived copy with a `> ⚠ Stale — superseded YYYY-MM-DD` note rather than rewriting history.
|
|
84
|
-
- **Compaction is bounded:** only `[FILLED YYYY-MM-DD]` gaps **older than 90 days** may be compacted, and only via a single marker prepended to `log.md
|
|
85
|
-
- **Log every prune** by prepending to `wiki/log.md
|
|
84
|
+
- **Compaction is bounded:** only `[FILLED YYYY-MM-DD]` gaps **older than 90 days** may be compacted, and only via a single marker prepended to `log.md` — a gap gets a `[FILLED]` stamp, never a deletion.
|
|
85
|
+
- **Log every prune** by prepending to `wiki/log.md`.
|
|
86
86
|
|
|
87
|
-
A full worked prune session (stale + superseded + conflict + gap compaction, all logged) is in
|
|
87
|
+
A full worked prune session (stale + superseded + conflict + gap compaction, all logged) is in `references/gardening-playbook.md`.
|
|
88
88
|
|
|
89
|
-
## Safety rails
|
|
89
|
+
## Safety rails
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Inherited from `../harness/references/wiki-protocol.md` — do not override them; each one guards against a loss you cannot undo.
|
|
92
92
|
|
|
93
93
|
1. **Preserve before overwrite.** Never overwrite an article without first copying the old version to `wiki/<topic>/_archive/<article>__YYYY-MM-DD.md`.
|
|
94
94
|
2. **Never auto-resolve a conflict.** Flag it; the human arbitrates.
|
|
95
|
-
3.
|
|
96
|
-
4. **
|
|
97
|
-
5. **Never touch an article whose `timestamp` is < 24h ago** without explicit user say-so. Why: it is likely still being worked. (`timestamp` is the OKF last-meaningful-edit field, ISO 8601 — see `../harness/references/wiki-protocol.md` "## Conventions".)
|
|
95
|
+
3. **The reserved files only grow.** Log every change in `wiki/log.md`, the OKF reserved change-log: new entries are **prepended at the top (newest first)**, ISO 8601 dates. `gaps.md` is the append-only one — new entries go at the bottom. Past entries in either are immutable: a gap gets a `[FILLED YYYY-MM-DD]` stamp, nothing is ever edited out or deleted.
|
|
96
|
+
4. **Never touch an article whose `timestamp` is < 24h ago** without explicit user say-so. Why: it is likely still being worked. (`timestamp` is the OKF last-meaningful-edit field, ISO 8601 — see `../harness/references/wiki-protocol.md` "## Conventions".)
|
|
98
97
|
|
|
99
98
|
## Anti-patterns
|
|
100
99
|
|
|
@@ -117,9 +116,7 @@ Route elsewhere when the request is not gardening an existing wiki:
|
|
|
117
116
|
|---------|----------|
|
|
118
117
|
| Build/bootstrap the wiki, run an inbox sweep, scaffold `01-TOOLS`, generate root `CLAUDE.md` | `harness` (`../harness/SKILL.md`) — it owns the engine |
|
|
119
118
|
| Turn a meeting transcript into a recap with action items + owners | `meeting-notes` (`../meeting-notes/SKILL.md`) |
|
|
120
|
-
| Author a decision record (ADR) with alternatives, status, review cadence | `decision-records` (you may *file* one; that skill *authors* the discipline
|
|
119
|
+
| Author a decision record (ADR) with alternatives, status, review cadence | `decision-records` (`../decision-records/SKILL.md`) — you may *file* one; that skill *authors* the discipline |
|
|
121
120
|
| Document a repeatable procedure step by step | `sop-builder` (`../sop-builder/SKILL.md`) |
|
|
122
|
-
| First-pass walkthrough of an unfamiliar codebase | `codebase-onboarding` |
|
|
123
|
-
| Run a literature / source-gathering research project | `research-ops` |
|
|
124
|
-
|
|
125
|
-
The sharp line: changing the wiki's machinery or filling it in bulk is `harness`. Exercising judgment over what an already-running wiki should contain and how it should be shaped is `knowledge-ops`.
|
|
121
|
+
| First-pass walkthrough of an unfamiliar codebase | `codebase-onboarding` (`../codebase-onboarding/SKILL.md`) |
|
|
122
|
+
| Run a literature / source-gathering research project | `research-ops` (`../research-ops/SKILL.md`) |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: medium-publishing
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when a finished article has to land on Medium correctly — profile vs publication, cross-posting under a canonical link so your own site keeps the SEO credit, import-tool failures, the 5-tag cap, pseudo-Markdown gotchas. NOT writing or headlining the piece (that is `medium-writing`), NOT cadence or earnings (that is `medium-strategy`)."
|
|
4
4
|
tags: [medium, publishing, cross-posting, canonical-url, seo, import-tool]
|
|
5
5
|
recommends: [medium-writing, medium-strategy, seo-geo, social-publisher]
|
|
6
6
|
origin: risco
|
|
@@ -10,13 +10,11 @@ origin: risco
|
|
|
10
10
|
|
|
11
11
|
Land a finished article on Medium with correct metadata: right destination, no duplicate-content penalty, valid tags, intact formatting. Writing the article is `../medium-writing/SKILL.md`; deciding when/where/how-often to publish and how it grows is `../medium-strategy/SKILL.md`. This skill is only the mechanics of getting bytes onto the platform with the right metadata attached.
|
|
12
12
|
|
|
13
|
-
## Reality check
|
|
13
|
+
## Reality check (2025-2026)
|
|
14
14
|
|
|
15
15
|
**The Medium API is closed to new integrations.** As of 2025-01-01 Medium issues no new integration tokens and accepts no new integrations; only tokens minted before that date still work. Why it matters: any plan that starts with "register a Medium API token and automate it" is dead on arrival for anyone who didn't already have one. Integration platforms confirm this — the Medium app in Make is marked legacy, and n8n's Medium credentials can no longer be newly configured.
|
|
16
16
|
|
|
17
|
-
So the default publishing path is **web editor + import tool + canonical link**, done through the UI. Treat the API as a legacy escape hatch (last section), not the plan.
|
|
18
|
-
|
|
19
|
-
Do not promise API automation. If the user asks "can I get a token and automate this?", the honest answer is almost always no — explain why and route them to the import path below.
|
|
17
|
+
So the default publishing path is **web editor + import tool + canonical link**, done through the UI. Treat the API as a legacy escape hatch (last section), not the plan — when asked "can I get a token and automate this?", the honest answer is almost always no, so say why and route to the import path below rather than promising automation.
|
|
20
18
|
|
|
21
19
|
## Decision table — pick your path
|
|
22
20
|
|
|
@@ -30,11 +28,9 @@ Branch on where the article already lives and what you control:
|
|
|
30
28
|
| You hold a pre-2025 API token and want automation | Legacy `POST /v1/users/{id}/posts` | `canonicalUrl` field in the request body |
|
|
31
29
|
| Destination is a publication you write for | Submit draft to the publication | Same as above; submission is separate from canonical |
|
|
32
30
|
|
|
33
|
-
When in doubt and the piece exists elsewhere, prefer the import tool — it gets canonical *and* backdate right in one step.
|
|
34
|
-
|
|
35
31
|
## Cross-post without an SEO penalty (the core job)
|
|
36
32
|
|
|
37
|
-
When the article already lives on your own site, you must tell search engines the
|
|
33
|
+
When the article already lives on your own site, you must tell search engines that the **origin** — your page, never the Medium URL — is canonical, or Google sees two copies and may credit Medium or neither. Two mechanisms, in order of preference:
|
|
38
34
|
|
|
39
35
|
**1. Import tool (preferred).** Pasting the original URL into Medium's import field does three things at once:
|
|
40
36
|
- imports the rendered content into a new draft,
|
|
@@ -54,8 +50,6 @@ Good: Use the import tool (canonical + backdate set automatically), or if
|
|
|
54
50
|
BEFORE publishing.
|
|
55
51
|
```
|
|
56
52
|
|
|
57
|
-
The canonical must point to the **origin** (your site), not to the Medium URL. The whole point is that your site keeps the SEO credit.
|
|
58
|
-
|
|
59
53
|
## When the import fails
|
|
60
54
|
|
|
61
55
|
The importer is an HTTP crawler hitting your URL; failures are crawl failures, not Medium bugs. Map the symptom to the cause:
|
|
@@ -98,9 +92,7 @@ Good: Convert the table to a labeled list, or screenshot/export it as an
|
|
|
98
92
|
Two outcomes, often confused:
|
|
99
93
|
|
|
100
94
|
- **Self-publish** puts the story on your own profile immediately.
|
|
101
|
-
- **Submit to a publication** routes the draft to that publication's editors
|
|
102
|
-
|
|
103
|
-
Why it sits pending: a publication is editorially controlled; submission is a request, not a publish action. If you're not yet a writer there, request access first; submitting otherwise goes nowhere.
|
|
95
|
+
- **Submit to a publication** routes the draft to that publication's editors, where it stays **pending** — not live — until one of them publishes it. A publication is editorially controlled, so submission is a request, not a publish action, and it only works if you are already an accepted writer there. If you're not, request access first; submitting otherwise goes nowhere.
|
|
104
96
|
|
|
105
97
|
## Legacy API — only if you hold a pre-2025 token
|
|
106
98
|
|
package/skills/n8n/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: n8n
|
|
3
|
-
description: "Use when operating a live n8n instance programmatically —
|
|
3
|
+
description: "Use when operating a live n8n instance programmatically — its REST API (`{host}/api/v1`, `X-N8N-API-KEY`) or the n8n-mcp server — to create, validate, test, activate, update, delete workflows and read executions on self-host or n8n.cloud. NOT designing the flow or its importable JSON (that is `automation-flows`), NOT another platform (`make`, `zapier`)."
|
|
4
4
|
tags: [n8n, automation, workflows, mcp, rest-api, no-code, integrations]
|
|
5
5
|
recommends: [automation-flows, automation-strategy, api-connector-builder, webhooks]
|
|
6
6
|
profiles: [full]
|
|
@@ -9,15 +9,11 @@ origin: risco
|
|
|
9
9
|
|
|
10
10
|
# n8n — operate a live instance over its REST API and MCP
|
|
11
11
|
|
|
12
|
-
You already have a workflow *design*
|
|
13
|
-
This skill is the **operate** half: push
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
server, both hitting the same instance.
|
|
17
|
-
|
|
18
|
-
Designing the flow itself (what fires it, how errors are handled, dedup) is **automation-flows** —
|
|
19
|
-
this skill *consumes* that skill's `references/n8n-workflow-json.md` payload; it does not re-teach
|
|
20
|
-
design.
|
|
12
|
+
You already have a workflow *design* — the trigger→steps→error shape and the importable JSON, which is
|
|
13
|
+
`automation-flows`' job and this skill does not re-teach it. This skill is the **operate** half: push
|
|
14
|
+
that JSON into a running n8n, validate it, test it, flip it live, watch its executions, and tear it
|
|
15
|
+
down safely — all without touching the UI. n8n has the richest programmatic story of the no-code
|
|
16
|
+
platforms: a first-party REST API **plus** a mature MCP server, both hitting the same instance.
|
|
21
17
|
|
|
22
18
|
## Connect first — REST API vs MCP
|
|
23
19
|
|
|
@@ -31,10 +27,10 @@ Two ways to drive the same instance. Pick by who is at the wheel.
|
|
|
31
27
|
| Surface | identical on self-host **and** `*.app.n8n.cloud` | same underlying API; hosted trial at `dashboard.n8n-mcp.com` |
|
|
32
28
|
|
|
33
29
|
**Version reality (verify at author time — n8n moves fast):**
|
|
34
|
-
- API base is `{host}/api/v1`. Self-host ships interactive Swagger at `/api/v1/docs`; **cloud does not
|
|
30
|
+
- API base is `{host}/api/v1`. Self-host ships interactive Swagger at `/api/v1/docs`; **cloud does not**
|
|
31
|
+
— on cloud, work from the docs.
|
|
35
32
|
- `POST /workflows/{id}/execute` (run-by-id) is **recent** (n8n PR #20234). Older instances lack it —
|
|
36
|
-
there, the only programmatic run is POSTing to a Webhook node's URL.
|
|
37
|
-
- The API surface is the SAME whether you self-host or run on `*.app.n8n.cloud`; only the host differs.
|
|
33
|
+
there, the only programmatic run is POSTing to a Webhook node's URL.
|
|
38
34
|
|
|
39
35
|
### `.env`
|
|
40
36
|
|
|
@@ -66,7 +62,8 @@ shapes rather than guessing — that is the single biggest reason to drive via M
|
|
|
66
62
|
## Dynamic lifecycle
|
|
67
63
|
|
|
68
64
|
create → **validate** → test → **activate** → manage → delete. A concrete sketch per step, curl and
|
|
69
|
-
n8n-mcp side by side
|
|
65
|
+
n8n-mcp side by side; every endpoint with pagination and scopes is in
|
|
66
|
+
`references/rest-api-cheatsheet.md`.
|
|
70
67
|
|
|
71
68
|
### 1. Validate (do this BEFORE create)
|
|
72
69
|
|
|
@@ -107,8 +104,9 @@ n8n_test_workflow { "id": "$ID" }
|
|
|
107
104
|
|
|
108
105
|
### 4. Activate — the step people miss
|
|
109
106
|
|
|
110
|
-
`active` in the create/update body
|
|
111
|
-
does nothing. You MUST call
|
|
107
|
+
`active` (and `tags`) in the create/update body are **read-only and silently ignored**. Setting
|
|
108
|
+
`"active": true` does nothing, which is why the workflow you just created never fires. You MUST call
|
|
109
|
+
the separate endpoint:
|
|
112
110
|
|
|
113
111
|
```bash
|
|
114
112
|
curl -sS -X POST "$N8N_API_URL/api/v1/workflows/$ID/activate" -H "X-N8N-API-KEY: $N8N_API_KEY"
|
|
@@ -137,7 +135,8 @@ omitted. n8n-mcp's `n8n_update_partial_workflow` applies a targeted, atomic batc
|
|
|
137
135
|
|
|
138
136
|
### 6. Delete — irreversible
|
|
139
137
|
|
|
140
|
-
`DELETE` is a **hard delete: no trash, no undo
|
|
138
|
+
`DELETE` is a **hard delete: no trash, no undo**, so export the current JSON first, every time — this
|
|
139
|
+
one is absolute because nothing downstream can recover the workflow if you skip it.
|
|
141
140
|
|
|
142
141
|
```bash
|
|
143
142
|
curl -sS "$N8N_API_URL/api/v1/workflows/$ID" -H "X-N8N-API-KEY: $N8N_API_KEY" > backup-$ID.json # export FIRST
|
|
@@ -147,7 +146,7 @@ curl -sS -X DELETE "$N8N_API_URL/api/v1/workflows/$ID" -H "X-N8N-API-KEY: $N8N_A
|
|
|
147
146
|
n8n_get_workflow { "id": "$ID" } → save output → n8n_delete_workflow { "id": "$ID" }
|
|
148
147
|
```
|
|
149
148
|
|
|
150
|
-
|
|
149
|
+
The same applies to a full replace: export before `PUT`.
|
|
151
150
|
|
|
152
151
|
## Governance
|
|
153
152
|
|
|
@@ -156,50 +155,23 @@ If you expose n8n-mcp to an agent, lock down destructive tools with the `DISABLE
|
|
|
156
155
|
key itself too — n8n supports scoped keys (e.g. grant `workflow:read` without `workflow:execute`).
|
|
157
156
|
Details in `references/n8n-mcp-tools.md`.
|
|
158
157
|
|
|
159
|
-
##
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
vs operate boundary: they decide the trigger/steps/error path; you push it live. Start there if the
|
|
180
|
-
flow's logic isn't settled yet.
|
|
181
|
-
- **automation-strategy** — whether n8n is even the right platform (cost model, self-host vs cloud) vs
|
|
182
|
-
Make/Zapier/Power Automate.
|
|
183
|
-
- **make / zapier / power-automate** — the other platforms' operate stories (Zapier and Power Automate
|
|
184
|
-
can't create flows via API — n8n's edge).
|
|
185
|
-
- **api-connector-builder** — a generic typed HTTP client with auth/pagination/backoff, when the answer
|
|
186
|
-
is real code, not a workflow.
|
|
187
|
-
- **webhooks** — building the inbound receiver *in your own app*; here webhooks are just n8n triggers.
|
|
188
|
-
|
|
189
|
-
## Checklist
|
|
190
|
-
|
|
191
|
-
- [ ] `.env` has `N8N_API_URL`/`N8N_HOST` + `N8N_API_KEY` (key from Settings → n8n API); key not logged.
|
|
192
|
-
- [ ] Payload has `name`, `nodes` (one trigger), `connections`, `settings` per automation-flows' schema;
|
|
193
|
-
node credentials referenced by store, never inlined.
|
|
194
|
-
- [ ] Validated (`n8n_validate_workflow` / `n8n_autofix_workflow`) before create when MCP is available.
|
|
195
|
-
- [ ] Created via `POST /workflows` or `n8n_create_workflow`; captured the returned `id`.
|
|
196
|
-
- [ ] Tested — `execute`-by-id (no input) or POST to the webhook URL (with input) — and the run succeeded.
|
|
197
|
-
- [ ] Activated via `POST /workflows/{id}/activate` (NOT `active:true` in the body).
|
|
198
|
-
- [ ] Before any DELETE or full-replace: exported the current JSON (hard delete, no trash).
|
|
199
|
-
- [ ] If MCP is exposed to an agent: `DISABLED_TOOLS` set and/or the API key scoped.
|
|
200
|
-
|
|
201
|
-
## References
|
|
202
|
-
|
|
203
|
-
- `references/rest-api-cheatsheet.md` — every workflow/execution endpoint with curl, pagination, scopes.
|
|
204
|
-
- `references/n8n-mcp-tools.md` — the management + node-knowledge tool list, the auth split, `DISABLED_TOOLS`.
|
|
205
|
-
- `references/auth-and-selfhost.md` — API-key creation, self-host vs cloud, Swagger, installing/pointing n8n-mcp.
|
|
158
|
+
## Anti-patterns
|
|
159
|
+
|
|
160
|
+
| Anti-pattern | Why it bites | Do instead |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| `"active": true` (or `tags`) in the create/update body | Read-only fields, silently ignored — the #1 "why is my workflow inactive" bug | `POST /workflows/{id}/activate`; set tags via their own endpoint |
|
|
163
|
+
| Passing runtime input to `/workflows/{id}/execute` | It accepts no custom input, and older instances 404 the endpoint entirely | Trigger a Webhook workflow by POSTing to its URL |
|
|
164
|
+
| `PUT` with a partial body, or `DELETE` on a live workflow | Full replace drops every node you omitted; delete is a hard delete with no trash | GET and export first; prefer `n8n_update_partial_workflow` for edits |
|
|
165
|
+
| A `typeVersion` the target instance doesn't have | Create succeeds; it fails only at activate/execute time | Validate via MCP, or test, before activating |
|
|
166
|
+
| Inlining node credential secrets, or expecting to read them back | Credentials are not fully manageable over the public API — it can create some, but never returns a secret | Provision in the UI or via `n8n_manage_credentials`, then reference existing credentials by id/name |
|
|
167
|
+
| Treating a successful API activation as proof it works | The public API historically skips a few UI-side activation validations, so a workflow can be "active" yet non-functional | Run it live after activating and check the execution |
|
|
168
|
+
|
|
169
|
+
## Route elsewhere
|
|
170
|
+
|
|
171
|
+
| If the ask is | Skill |
|
|
172
|
+
|---|---|
|
|
173
|
+
| Designing the flow (trigger/steps/error path, dedup) and producing the importable JSON | `automation-flows` — start there if the logic isn't settled |
|
|
174
|
+
| Whether n8n is the right platform at all — cost model, self-host vs cloud | `automation-strategy` |
|
|
175
|
+
| Operating a different platform | `make`, `zapier`, `power-automate` (neither Zapier nor Power Automate can create flows via API — n8n's edge) |
|
|
176
|
+
| A generic typed HTTP client with auth/pagination/backoff — real code, not a workflow | `api-connector-builder` |
|
|
177
|
+
| The inbound webhook receiver in your own app (here webhooks are only n8n triggers) | `webhooks` |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: notion-connector
|
|
3
|
-
description: "Use when wiring
|
|
3
|
+
description: "Use when wiring server code or a cron job to Notion as an ops backend over its HTTP API: pushing or mirroring database rows, two-way sync without duplicates, page blocks, or an integration broken by the 2025-09-03 data-source split. NOT generic REST wiring (that is `api-connector-builder`), NOT inbound Notion webhook events (that is `webhooks`)."
|
|
4
4
|
tags: [notion, ops-backend, api-integration, databases, sync]
|
|
5
5
|
recommends: [api-connector-builder, webhooks, automation-flows, spreadsheet-ops, secure-coding]
|
|
6
6
|
origin: risco
|
|
@@ -14,24 +14,7 @@ write page blocks. This skill owns the **outbound** Notion API surface only —
|
|
|
14
14
|
the database/data-source data model, property-type write shapes, and the
|
|
15
15
|
rate-limit/pagination discipline that the API forces on you.
|
|
16
16
|
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
**Pin the `Notion-Version` per request, and resolve the data source before you
|
|
20
|
-
query.** Post `2025-09-03` a database is a *container* of one or more data
|
|
21
|
-
sources — not a queryable table. Skip either half and you get silent 404s on
|
|
22
|
-
code that worked last year.
|
|
23
|
-
|
|
24
|
-
- Current major version: **`2025-09-03`** (the SDK default). Latest: **`2026-03-11`**.
|
|
25
|
-
- Behavior differs across versions; an unpinned client drifts when the default moves.
|
|
26
|
-
|
|
27
|
-
## When to use / when NOT to use
|
|
28
|
-
|
|
29
|
-
**Use when:** treating a Notion database as a CRM / task tracker / content
|
|
30
|
-
calendar from code; pushing or pulling rows on a schedule; two-way sync that
|
|
31
|
-
must not duplicate on re-run; building or reading page block content; migrating
|
|
32
|
-
a `2022-06-28` integration that broke when someone added a second data source.
|
|
33
|
-
|
|
34
|
-
**Route elsewhere:**
|
|
17
|
+
## Route elsewhere
|
|
35
18
|
|
|
36
19
|
| Situation | Route to |
|
|
37
20
|
|---|---|
|
|
@@ -50,10 +33,12 @@ a `2022-06-28` integration that broke when someone added a second data source.
|
|
|
50
33
|
3. **Share the target database/page with the integration** in the Notion UI
|
|
51
34
|
(the page `•••` menu → Connections). *Skip this and every call 404s or
|
|
52
35
|
returns empty* — the integration sees nothing it was not explicitly granted.
|
|
53
|
-
4. **Construct the SDK client with a pinned
|
|
54
|
-
`@notionhq/client` v5.12.0+ (latest 5.22.0, 2026-05-19); its default
|
|
55
|
-
`notionVersion` is
|
|
56
|
-
The default and method names below are
|
|
36
|
+
4. **Construct the SDK client with a pinned `Notion-Version`.** Official JS SDK
|
|
37
|
+
is `@notionhq/client` v5.12.0+ (latest 5.22.0, 2026-05-19); its default
|
|
38
|
+
`notionVersion` is the current major **`2025-09-03`**, and it supports the
|
|
39
|
+
latest **`2026-03-11`** if you opt in. The default and method names below are
|
|
40
|
+
stable across the whole 5.x line. Behavior differs across versions, so pin it
|
|
41
|
+
per client (or per request) — an unpinned client drifts when the default moves.
|
|
57
42
|
|
|
58
43
|
```ts
|
|
59
44
|
import { Client } from "@notionhq/client"; // v5.12.0+ (latest 5.22.0)
|
|
@@ -66,9 +51,11 @@ const notion = new Client({
|
|
|
66
51
|
|
|
67
52
|
## The database → data source model (biggest gotcha)
|
|
68
53
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
54
|
+
Post `2025-09-03` a database is a **container** of one or more data sources, not
|
|
55
|
+
a queryable table: it holds a `data_sources` array and each data source has its
|
|
56
|
+
**own schema**. Resolve the data source *before* you query — query and read
|
|
57
|
+
schema against it, not against the database, or code that worked last year 404s
|
|
58
|
+
silently.
|
|
72
59
|
|
|
73
60
|
| You have… | Do this |
|
|
74
61
|
|---|---|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: planetscale
|
|
3
|
-
description: "Use when operating PlanetScale serverless MySQL
|
|
3
|
+
description: "Use when operating PlanetScale (Vitess serverless MySQL) — branches and the `pscale` CLI, schema changes through deploy requests (Online DDL cutover, ~30-min revert window), tables without foreign keys, or the edge HTTP driver. NOT MySQL engine work like EXPLAIN or index choice (that is `mysql`), NOT generic migration theory (that is `db-migrations`)."
|
|
4
4
|
tags: [planetscale, vitess, mysql, deploy-requests, serverless-db]
|
|
5
5
|
recommends: [mysql, db-migrations, prisma-orm, drizzle-orm, github-actions, postgresdb]
|
|
6
6
|
origin: risco
|
|
@@ -17,34 +17,15 @@ then **cuts over** with no table lock. Because Online DDL and sharding are the p
|
|
|
17
17
|
gravity, you **design without foreign keys** (FKs are now an opt-in but unsharded-only feature). This
|
|
18
18
|
skill owns that workflow — not MySQL the engine.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Heuristic for the boundary: **would this answer be identical on RDS MySQL? Then it is not this skill.**
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- Wiring deploy requests into CI (GitHub Actions) or a branch-per-PR preview database.
|
|
30
|
-
|
|
31
|
-
**When NOT to use:**
|
|
32
|
-
|
|
33
|
-
- A slow query, an `EXPLAIN` plan, an index decision, JSON columns, locking — that is MySQL-engine
|
|
34
|
-
work. The closest built sibling for engine-level relational guidance is `../postgresdb/SKILL.md`
|
|
35
|
-
(Postgres, but the engine-thinking transfers); pure MySQL tuning routes to the `mysql` sibling.
|
|
36
|
-
Heuristic: **would this answer be identical on RDS MySQL? Then it is not this skill.**
|
|
37
|
-
- PostgreSQL engine/design — even PlanetScale's managed Postgres SQL semantics → `../postgresdb/SKILL.md`.
|
|
38
|
-
PlanetScale sells Postgres too, but this skill is strictly the **Vitess/MySQL branch+deploy-request** flow.
|
|
39
|
-
- Engine-agnostic migration *theory* (expand-contract, backfill ordering) → the `db-migrations` sibling.
|
|
40
|
-
Here you get the concrete PlanetScale realization, not the theory.
|
|
41
|
-
- Neon's Postgres copy-on-write branches → the `neon` sibling. Supabase's Postgres BaaS → `supabase`.
|
|
42
|
-
- ORM client ergonomics (Prisma `updateMany`, Drizzle query builder) → `prisma-orm` / `../drizzle-orm/SKILL.md`.
|
|
43
|
-
This skill owns only the PlanetScale-specific knobs those ORMs expose (`relationMode`, serverless driver adapter).
|
|
44
|
-
|
|
45
|
-
Deep dives: [deploy-requests](references/deploy-requests.md) (lifecycle states, queue/gating, lint
|
|
46
|
-
errors, revert edge cases, declarative vs imperative) · [no-foreign-keys](references/no-foreign-keys.md)
|
|
47
|
-
(emulated relations, ORM `relationMode`, the unsharded FK opt-in, Bad→Good schemas).
|
|
22
|
+
| When the question is really about | Route to |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| A slow query, an `EXPLAIN` plan, an index decision, JSON columns, locking | `../mysql/SKILL.md` for MySQL-engine work; `../postgresdb/SKILL.md` when you want the transferable engine reasoning |
|
|
25
|
+
| PostgreSQL engine/design — even PlanetScale's own managed Postgres SQL semantics | `../postgresdb/SKILL.md`. PlanetScale sells Postgres too; this skill is strictly the **Vitess/MySQL branch+deploy-request** flow |
|
|
26
|
+
| Engine-agnostic migration *theory* (expand-contract, backfill ordering) | `../db-migrations/SKILL.md`. Here you get the concrete PlanetScale realization, not the theory |
|
|
27
|
+
| Postgres copy-on-write branches | `../neon/SKILL.md`. Postgres BaaS → `../supabase/SKILL.md` |
|
|
28
|
+
| ORM client ergonomics (Prisma `updateMany`, Drizzle query builder) | `../prisma-orm/SKILL.md` / `../drizzle-orm/SKILL.md`. This skill owns only the PlanetScale-specific knobs those ORMs expose (`relationMode`, serverless driver adapter) |
|
|
48
29
|
|
|
49
30
|
## Mental model
|
|
50
31
|
|
|
@@ -149,9 +130,14 @@ datasource db {
|
|
|
149
130
|
```
|
|
150
131
|
|
|
151
132
|
With Drizzle, model the relation in app code (`relations()`), index the join column, and skip the
|
|
152
|
-
`references()`-backed FK constraint at the DB layer.
|
|
153
|
-
|
|
154
|
-
|
|
133
|
+
`references()`-backed FK constraint at the DB layer.
|
|
134
|
+
|
|
135
|
+
| Will this table shard? | FK strategy | Notes |
|
|
136
|
+
| --- | --- | --- |
|
|
137
|
+
| Yes, or unsure | No DB FK — emulate in app/ORM | Default. Index the relation column; cascade in code. |
|
|
138
|
+
| Never (small, bounded, unsharded) | Unsharded FK opt-in *is* acceptable | Accept Online DDL friction; document why it won't shard. |
|
|
139
|
+
|
|
140
|
+
See [no-foreign-keys](references/no-foreign-keys.md) for emulated cascades, ORM specifics, and the opt-in caveats.
|
|
155
141
|
|
|
156
142
|
## Connecting
|
|
157
143
|
|
|
@@ -196,7 +182,7 @@ installs `pscale`, authenticates with a service token (`PLANETSCALE_SERVICE_TOKE
|
|
|
196
182
|
|
|
197
183
|
For a **branch-per-PR preview database**, create a PlanetScale branch named after the PR head, run the
|
|
198
184
|
app's migrations against it, and tear the branch down when the PR closes. The orchestration (matrix,
|
|
199
|
-
secrets, cleanup-on-close) is generic CI — defer the Actions plumbing to
|
|
185
|
+
secrets, cleanup-on-close) is generic CI — defer the Actions plumbing to `../github-actions/SKILL.md`
|
|
200
186
|
and keep the PlanetScale verbs here.
|
|
201
187
|
|
|
202
188
|
## Anti-patterns
|
|
@@ -210,14 +196,3 @@ and keep the PlanetScale verbs here.
|
|
|
210
196
|
| Treating revert as available forever | The window is **~30 min** and excludes dropped tables/cols and FK changes | Plan rollbacks as new forward deploys |
|
|
211
197
|
| Deploying without reading `deploy-request diff` | You ship DDL you never saw; surprise table rewrites | Always run the diff before `deploy` |
|
|
212
198
|
| Inventing a driver name (`@planetscale/serverless`, `planetscale-js`) | There is no such package; install fails | The package is exactly `@planetscale/database` |
|
|
213
|
-
|
|
214
|
-
## Decision: FK strategy by sharding posture
|
|
215
|
-
|
|
216
|
-
| Will this table shard? | FK strategy | Notes |
|
|
217
|
-
| --- | --- | --- |
|
|
218
|
-
| Yes, or unsure | No DB FK — emulate in app/ORM | Default. Index the relation column; cascade in code. |
|
|
219
|
-
| Never (small, bounded, unsharded) | Unsharded FK opt-in *is* acceptable | Accept Online DDL friction; document why it won't shard. |
|
|
220
|
-
|
|
221
|
-
When the question is really about reading a plan, picking an index, or query latency, that is engine
|
|
222
|
-
work — route to the `mysql` sibling (or `../postgresdb/SKILL.md` for the transferable engine
|
|
223
|
-
reasoning). This skill stops at the Vitess platform boundary.
|
|
@@ -58,13 +58,13 @@ model Order {
|
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
ORM-client ergonomics beyond this knob belong to
|
|
61
|
+
ORM-client ergonomics beyond this knob belong to `../../prisma-orm/SKILL.md`, not here.
|
|
62
62
|
|
|
63
63
|
## Drizzle: app-level relations
|
|
64
64
|
|
|
65
65
|
Drizzle models relations in app code via `relations()` and queries them with the relational API. On
|
|
66
66
|
PlanetScale you index the join column and skip the `references()`-backed DB constraint; the relation
|
|
67
|
-
lives in code, not in the database. The query-builder side is
|
|
67
|
+
lives in code, not in the database. The query-builder side is `../../drizzle-orm/SKILL.md`.
|
|
68
68
|
|
|
69
69
|
## The unsharded FK opt-in
|
|
70
70
|
|