@vegastack/skills 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +4 -2
  2. package/dist/index.js +38 -45
  3. package/package.json +1 -1
  4. package/skill/architect/SKILL.md +68 -0
  5. package/skill/architect/agents/openai.yaml +4 -0
  6. package/skill/architect/assets/adr-template.md +21 -0
  7. package/skill/architect/assets/arch-template.md +20 -0
  8. package/skill/architect/references/advisory.md +102 -0
  9. package/skill/architect/references/ai-agents.md +95 -0
  10. package/skill/architect/references/data.md +90 -0
  11. package/skill/architect/references/infra.md +128 -0
  12. package/skill/architect/references/mobile.md +78 -0
  13. package/skill/architect/references/pinned-facts.md +108 -0
  14. package/skill/architect/references/principles.md +91 -0
  15. package/skill/architect/references/project-profile.md +37 -0
  16. package/skill/architect/references/security.md +97 -0
  17. package/skill/architect/references/stack.md +38 -0
  18. package/skill/architect/references/web.md +152 -0
  19. package/skill/architect/refresh/REFRESH.md +29 -0
  20. package/skill/architect/refresh/sources.json +244 -0
  21. package/skill/skill-maintainer/references/release-ops.md +11 -15
  22. package/skill/skill-maintainer/refresh/REFRESH.md +3 -3
  23. package/skill-integrity.json +20 -44
  24. package/skill/arch-guardian/SKILL.md +0 -84
  25. package/skill/arch-guardian/agents/openai.yaml +0 -4
  26. package/skill/arch-guardian/assets/adr-template.md +0 -25
  27. package/skill/arch-guardian/assets/answers-example.json +0 -10
  28. package/skill/arch-guardian/assets/architecture-profile.json +0 -13
  29. package/skill/arch-guardian/assets/architecture-profile.schema.json +0 -31
  30. package/skill/arch-guardian/assets/deployment-review-template.md +0 -24
  31. package/skill/arch-guardian/assets/service-design-template.md +0 -33
  32. package/skill/arch-guardian/assets/threat-model-template.md +0 -34
  33. package/skill/arch-guardian/references/advisory-report.md +0 -65
  34. package/skill/arch-guardian/references/architecture/agent-product.md +0 -22
  35. package/skill/arch-guardian/references/architecture/ai-cost.md +0 -24
  36. package/skill/arch-guardian/references/architecture/ai-data-boundaries.md +0 -21
  37. package/skill/arch-guardian/references/architecture/ai-evals.md +0 -28
  38. package/skill/arch-guardian/references/architecture/connectors-sandbox.md +0 -39
  39. package/skill/arch-guardian/references/architecture/data-memory.md +0 -25
  40. package/skill/arch-guardian/references/architecture/delivery-operations.md +0 -34
  41. package/skill/arch-guardian/references/architecture/durable-execution.md +0 -45
  42. package/skill/arch-guardian/references/architecture/flutter.md +0 -26
  43. package/skill/arch-guardian/references/architecture/foundation.md +0 -31
  44. package/skill/arch-guardian/references/architecture/hosting-reliability.md +0 -37
  45. package/skill/arch-guardian/references/architecture/identity-tenancy.md +0 -37
  46. package/skill/arch-guardian/references/architecture/model-lifecycle.md +0 -20
  47. package/skill/arch-guardian/references/architecture/models-observability.md +0 -23
  48. package/skill/arch-guardian/references/architecture/realtime-channels.md +0 -16
  49. package/skill/arch-guardian/references/architecture/security-privacy.md +0 -27
  50. package/skill/arch-guardian/references/architecture/topology-monorepo.md +0 -47
  51. package/skill/arch-guardian/references/architecture/web.md +0 -29
  52. package/skill/arch-guardian/references/foundation-compatibility.json +0 -44
  53. package/skill/arch-guardian/references/golden-patterns.md +0 -43
  54. package/skill/arch-guardian/references/profile-governance.md +0 -40
  55. package/skill/arch-guardian/references/rule-model.json +0 -36
  56. package/skill/arch-guardian/references/workflows.md +0 -48
  57. package/skill/arch-guardian/refresh/REFRESH.md +0 -47
  58. package/skill/arch-guardian/refresh/sources.json +0 -1171
  59. package/skill/arch-guardian/scripts/lib.mjs +0 -48
  60. package/skill/arch-guardian/scripts/profile-tool.mjs +0 -217
  61. package/skill/arch-guardian/scripts/refresh-evidence.mjs +0 -366
  62. package/skill/arch-guardian/scripts/schema-validate.mjs +0 -63
  63. package/skill/arch-guardian/scripts/validate-profile.mjs +0 -65
  64. package/skill/arch-guardian/scripts/verify-corpus.mjs +0 -136
@@ -0,0 +1,128 @@
1
+ # Infra — hosting, CI/CD, observability
2
+
3
+ ## Hosting targets
4
+
5
+ Two sanctioned targets, recorded per project in `.vegastack/arch.md`:
6
+
7
+ - **Cloudflare Workers via OpenNext** — the default for public web products. Once a project
8
+ commits to Cloudflare, never stand up a parallel Vercel deploy path (deploy paths drift).
9
+ Shared packages must still *work* on Vercel for downstream consumers — that's portability,
10
+ not a deploy target.
11
+ - **Self-managed servers** (Hetzner-class, Docker; Coolify for push-to-deploy) — when
12
+ self-hosting is a product requirement, the workload needs long-lived processes (EVE, heavy
13
+ workers), or platform independence justifies ~30 min/month of real ops.
14
+ - Vercel only by explicit, recorded per-project exception (e.g. EVE-hosted workloads).
15
+ Internal/admin apps that need no edge features may run plain `next start` in Docker —
16
+ OpenNext is the default, not a ritual.
17
+
18
+ ## Cloudflare discipline
19
+
20
+ - Provision only what the current phase uses. Queues, KV, Durable Objects, Workflows are
21
+ all trigger-gated: DO when live collaboration/presence actually ships (hibernating
22
+ WebSockets make it cheap then — see pinned-facts); Queues when webhook/event volume is
23
+ real; never scaffolded ahead of need. Delete stale Workers, Hyperdrive configs, and
24
+ buckets — with an explicit create/delete accounting before touching anything, and
25
+ `wrangler` used carefully.
26
+ - Multi-env via the Workers environments feature (`env.*`) — never separate top-level
27
+ Workers per environment. One Hyperdrive per environment, shared by every service hitting
28
+ the same database.
29
+ - Naming: hyphen-only across all Cloudflare resources; purge inconsistent legacy names.
30
+ - Domains: production on the `vegastack.com` apex/subdomains; non-prod environments under
31
+ `*.vegastack.dev`. Every Worker sets `workers_dev: false` + `custom_domain: true` — the
32
+ default `*.workers.dev` origin bypasses Cloudflare Access, so leaving it on exposes a
33
+ gated Worker unauthenticated (this is security, not cosmetics). Preview environments are
34
+ access-protected by default; only production is public.
35
+ - Environments are `dev` / `preview` / `production` via the Workers `env.*` feature; the
36
+ `staging` git branch deploys to the `preview` environment — there is no fourth Worker
37
+ environment unless a project records one. Secrets are set per environment
38
+ (`wrangler secret put X --env production`). Local env files: `.env` feeds `next dev`,
39
+ `.dev.vars` feeds `wrangler dev`/Miniflare — both gitignored, both with committed
40
+ `.example` companions.
41
+ - No Cloudflare Images — optimize with `sharp` at build/upload time and serve from R2 (the
42
+ paid add-on solves a problem `sharp` + free egress already solve).
43
+ - Runtime constraints are architectural facts: no TCP clients, per-request DB connections
44
+ (data.md), and OpenNext trails vanilla Next.js — check OpenNext docs per feature instead
45
+ of assuming. Two dated specifics: Turbopack is supported since adapter v1.15.0 (the old
46
+ breakage is fixed; re-verify only on older pins); `proxy.ts`/Node middleware does NOT
47
+ work on OpenNext Cloudflare as of 2026-08 (open issues opennextjs-cloudflare#962/#1277,
48
+ workers-sdk#13755/#13937) — don't design a Cloudflare-hosted feature around `proxy.ts`;
49
+ re-check the trackers before assuming it shipped.
50
+ - Edge/CDN caching never bypasses live authorization — revoked, expired, or
51
+ password-protected content is re-checked even when the artifact is cached.
52
+ - Cloudflare Tunnel is the default for exposing self-hosted services and remote dev
53
+ previews (already paid for via the Workers plan). Cloudflare Access gates paths by data
54
+ sensitivity with email allowlists — not one site-wide gate.
55
+
56
+ ## Self-managed discipline
57
+
58
+ - Containers hardened: non-root user, `cap_drop: [ALL]`, `read_only: true` where runtime
59
+ paths allow; healthchecks on every service. Migrations and storage provisioning run in
60
+ the app container's own entrypoint under a Postgres advisory lock (safe when replicas
61
+ race on boot) — not a separate bootstrap deployable, unless a project records a concrete
62
+ reason for one (the shipped self-host pattern deliberately avoids an extra init
63
+ container).
64
+ - Ship `docker compose up` as the self-host story: bundle only Postgres + MinIO-class
65
+ essentials; everything else (vector store, gateway, vault) is connect-your-own.
66
+ - Server sizing: SSD, compute, and RAM over disk capacity, optimized for ROI within the
67
+ budget MK states for that server (ask if none was stated — don't guess one); Coolify
68
+ itself needs ~2GB RAM and real patching (pinned-facts). Cloud infra beyond Cloudflare
69
+ goes through Terraform, IAM scoped narrowly per purpose and region.
70
+ - Any infra cleanup (disks, stale resources, runners) needs explicit authorization first,
71
+ scoped to verified-stale items — never blanket cleanup.
72
+
73
+ ## CI/CD
74
+
75
+ - Never commit, tag, push, merge, publish, deploy, or create paid/cloud resources without
76
+ MK's explicit go-ahead for that step — this holds even in fully autonomous runs (it is
77
+ the red line, stated identically in SKILL.md).
78
+ - Build passes before any commit. When committing: review the complete uncommitted diff
79
+ (not just this session's), draft a conventional-commit message covering all of it, wait
80
+ for approval.
81
+ - Package manager is locked per project — read it from the repo, pin the exact version
82
+ (corepack/bun), never silently substitute.
83
+ - Branch protection on main/staging/develop (no force-push), branch-naming enforced
84
+ server-side and in a pre-push hook. DB migrations apply via CI only (data.md).
85
+ - CI is cost-managed, not maximal: path-condition expensive jobs (VRT, contract tests) so
86
+ docs/skills-only changes skip them; push heavy verification into local pre-commit/pre-push
87
+ hooks and self-hosted runners; hosted Actions minutes are a tracked budget. Verification
88
+ is local-first — CI verifies that it happened, via a committed receipt (a signed
89
+ `.gates/receipt.json` bound to the git tree hash) rather than re-executing browser
90
+ suites. A receipt is attestation, not proof — skipping a gate becomes visible, not
91
+ impossible.
92
+ - Wire every architectural guard script (import boundaries, runtime gravity, route-wrapper
93
+ ratchet) into the one composed check command — a separate script someone forgets to run
94
+ doesn't exist.
95
+ - Green CI is necessary, never sufficient: a unit is done after a real
96
+ boot → auth → reach → mutate → verify pass against live infra. On CI failure:
97
+ diagnose and report the root cause first; fix second.
98
+ - Releases via Changesets + GitHub Actions. MK enters npm OTP/2FA and other credentials
99
+ himself — never the agent. Node 24 standard; deprecated Actions versions are routine
100
+ housekeeping, fixed proactively.
101
+
102
+ ## Observability (small-team baseline)
103
+
104
+ - Structured JSON logs (pino) to stdout with OTel-shaped fields (trace/request/org context
105
+ auto-injected) — OTel-compatible by convention now, full OTel SDK/collector only when
106
+ cross-service trace correlation becomes a real pain, not before.
107
+ - The append-only Postgres event log is the authoritative telemetry source; metrics/log
108
+ tables are derived and disposable (30-day raw, 13-month rollups, compress after ~7 days;
109
+ TimescaleDB opportunistic with partition+BRIN fallback).
110
+ - On Cloudflare, use the built-in free tier first: Workers Logs (200k/day, 3-day
111
+ retention) and the analytics dashboard cost nothing; note Workers tracing starts billing
112
+ 2026-10-01, and OTLP export needs Workers Paid.
113
+ - Alerting honest to team size: an uptime monitor (Uptime Kuma-class) + a cron that checks
114
+ error-rate thresholds in the event table and posts to Slack, plus a dead-man's-switch
115
+ ping for silent job failures. No paging/SLO/on-call ceremony — that practice is
116
+ deliberately undefined until the team needs it; propose per project, don't invent doctrine.
117
+
118
+ ## Incidents
119
+
120
+ - Active production incident: diagnose first (root cause with evidence), fix second — the
121
+ standing diagnose-before-fix rule applies under pressure too. Rolling back a deploy IS a
122
+ deploy: it still needs MK's go-ahead — reach him with the evidence and the recommended
123
+ rollback rather than acting; mitigation that doesn't deploy (feature-level disable via
124
+ config, traffic block) can proceed and be reported.
125
+ - Every real incident gets a short postmortem in the project's `docs/postmortems/`
126
+ (established precedent): what happened, root cause, the guard that now prevents it.
127
+ Codify the recurring correction (advisory.md) — an incident that doesn't change a rule
128
+ or a check will repeat.
@@ -0,0 +1,78 @@
1
+ # Mobile — Flutter production doctrine
2
+
3
+ **The Flutter app is a separate repo from the web/API repo** — it consumes the Next.js
4
+ REST/OpenAPI contract as one more client, never a `mobile/` directory in the web monorepo
5
+ (ADR-recorded, corroborated three ways; an expensive structural call to get wrong).
6
+
7
+ Flutter is the production mobile framework when a product needs a mobile app (not all do —
8
+ the profile records it). Baseline: Flutter 3.44.x stable; Impeller is the default renderer
9
+ on iOS and Android API 29+ (falls back below 29 — test one API<29 device before shipping).
10
+ Package versions here were verified 2026-08; re-verify on pub.dev before pinning.
11
+
12
+ Evidence tiers in this file: rules drawn from the shipped VegaStack app are stated plainly;
13
+ rules from official-docs research that MK has not yet ratified are tagged "(inferred)" —
14
+ confirm those on first use, per SKILL.md.
15
+
16
+ ## Architecture (official-guidance derived — inferred where the shipped app is silent)
17
+
18
+ - MVVM per official flutter.dev/app-architecture: View (widget, no logic) → ViewModel
19
+ (state + commands, 1:1 with its View) → Repository (source of truth, caching/retry,
20
+ never depends on another repository) → Service (thin stateless API/platform wrapper).
21
+ Skip the optional domain/use-case layer until logic is reused across ≥2 ViewModels.
22
+ - Project structure is layer-first: `lib/{data, domain, ui, routing, config}`, feature
23
+ folders nested inside `ui/`, shared widgets in `ui/core/`. (Blog "feature-first is the
24
+ standard" claims don't survive verification — the official reference app, Compass, is
25
+ layer-first. Feature-first is a valid escalation once app/team size demands it.)
26
+ - Class names mirror roles: `HomeViewModel`, `HomeScreen`, `UserRepository`,
27
+ `ClientApiService`.
28
+
29
+ ## State management — lean by default
30
+
31
+ - Plain `ChangeNotifier`/`ValueNotifier` ViewModels with hand-wired constructor injection
32
+ in `main.dart`. Zero extra dependencies, zero codegen — this matches both official
33
+ guidance ("personal preference") and what VegaStack has actually shipped.
34
+ - Escalate to Riverpod only when async state genuinely needs sharing across ≥3 widgets,
35
+ tests need provider-override mocking, or a second app shares a state-heavy module.
36
+ No get_it — official docs steer away from service locators; `provider` is the official
37
+ DI pick if constructor wiring ever gets unwieldy.
38
+
39
+ ## Networking & auth
40
+
41
+ - One `dio` client centralized in a single `ApiClient` — never scattered HTTP calls.
42
+ The app consumes the same contract-first REST API as the web app (web.md).
43
+ - Auth is the same Better Auth instance as web, via the bearer plugin: capture the token
44
+ from the `set-auth-token` response header on sign-in; store it in
45
+ `flutter_secure_storage` (never shared_preferences); attach `Authorization: Bearer` via
46
+ a dio interceptor; clear storage and route to sign-in on 401.
47
+ - Do NOT depend on `better_auth_flutter` (0.1.0, negligible adoption as of 2026-08) —
48
+ hand-roll the interceptor; revisit at a real 1.0.
49
+ - `shared_preferences` for non-secret local metadata only. `drift` only if genuine
50
+ offline/relational needs exist — never speculatively.
51
+
52
+ ## Design system on mobile
53
+
54
+ - Material 3 (default since 3.16); semantic colors via a hand-authored `ColorScheme` plus
55
+ `ThemeExtension` for tokens outside Material's roles — mirroring the web design-system
56
+ token names 1:1 from one Dart source of truth.
57
+ - House taste mapped: `CardTheme(elevation: 0)` with `outlineVariant` borders (flat,
58
+ borders-only); TextTheme capped at `FontWeight.w600`, never bold; subtle motion with
59
+ reduced-motion respected; Lucide-style iconography.
60
+
61
+ ## Navigation, models, testing, deploy
62
+
63
+ - Navigation: the shipped app uses plain `Navigator`; `go_router` is the official Flutter
64
+ team pick for route-heavy apps (inferred) — adopt it when deep links/route state demand
65
+ it, not by reflex.
66
+ - Models: the shipped app hand-writes all models — stay hand-written by default; freezed +
67
+ json_serializable only when codegen demonstrably earns its build cost (inferred
68
+ threshold, not MK-ratified).
69
+ - Test where MVVM pays off: unit-test ViewModels and Repositories; widget-test critical
70
+ screens; integration tests only for can't-ship-broken flows (sign-in, payment). Golden
71
+ tests, if adopted: `alchemist` over the discontinued `golden_toolkit` (inferred — no
72
+ VegaStack golden-test precedent yet).
73
+ - Deploy: GitHub Actions is the house CI; Fastlane for store signing/upload and real build
74
+ flavors (`--flavor` + per-env entry points) are the researched defaults (inferred — no
75
+ shipped store-deploy precedent yet; confirm before wiring).
76
+
77
+ Undecided (ask MK rather than assume): push-notification provider preference, offline/sync
78
+ expectations per product, store-release cadence.
@@ -0,0 +1,108 @@
1
+ # Pinned platform facts
2
+
3
+ Dated, source-verified facts that change architecture decisions and that models routinely
4
+ get wrong from stale training data. This is the ONLY file in this skill that goes stale by
5
+ itself — the weekly refresh (see refresh/REFRESH.md) re-verifies it. When a recommendation
6
+ leans on a fact older than 60 days, re-verify that one fact against its source first.
7
+
8
+ All facts below verified 2026-08-12.
9
+
10
+ ## Cloudflare
11
+
12
+ - **R2 egress is $0 at any volume.** A 500GB-stored / 2TB-served workload is ~$191/mo on
13
+ S3 vs ~$7.50/mo on R2. Reaching for S3+CloudFront "to control egress" solves a problem R2
14
+ doesn't have. Lifecycle rules, bucket locks, event notifications, and Infrequent Access
15
+ are all live — note IA transitions are one-way via lifecycle (IA→Standard needs a manual
16
+ CopyObject). [developers.cloudflare.com/r2/pricing]
17
+ - **Hyperdrive supports PostgreSQL 9.0–17.x — PG 18 is NOT supported.** Target Postgres 17
18
+ for any Hyperdrive-fronted database; re-check the supported-versions page before ever
19
+ moving to 18. Hyperdrive also supports MySQL (GA 2026-08-07) and private DBs via Workers
20
+ VPC. [developers.cloudflare.com/hyperdrive/reference/supported-databases-and-features]
21
+ - **Durable Objects default to SQLite storage** (real SQL, transactions, point-in-time
22
+ recovery), and **hibernating WebSocket DOs bill ~$0 while idle** — one-DO-per-room is
23
+ cost-competitive with Redis+socket.io for mostly-idle connections.
24
+ [developers.cloudflare.com/durable-objects]
25
+ - **Workflows: 10,000 steps default / 25,000 max, 365-day sleeps — and per-step billing
26
+ since 2026-08-10.** High-step-count designs now have a real cost dimension.
27
+ [developers.cloudflare.com/workflows]
28
+ - **Browser Rendering is metered by duration AND concurrency** ($0.09/browser-hour + $2 per
29
+ extra concurrent browser) — batch scraping through a queue; it is not free headless Chrome.
30
+ [developers.cloudflare.com/browser-rendering]
31
+ - **R2/KV/Workflows event notifications route through Queues "event subscriptions"** — a
32
+ Queue consumer covers platform state changes; don't build a bespoke webhook receiver.
33
+ - **D1 read replication only helps via the Sessions API** (`withSession(bookmark)`);
34
+ without it every query still hits the primary.
35
+
36
+ ## Next.js (16.3, released 2026-08-03)
37
+
38
+ - **PPR flags are gone** — `experimental.ppr` no longer exists; partial prerendering is
39
+ part of `cacheComponents: true` (which also replaced `dynamicIO`). [nextjs.org/blog]
40
+ - **`middleware.ts` is replaced by `proxy.ts` running on Node** — full fs/crypto/native
41
+ package access in request interception. Remember: proxy is still never the auth boundary.
42
+ - **The Adapter API is stable since 16.2** — Vercel's adapter and Cloudflare's OpenNext
43
+ adapter share the same public contract, but Cloudflare's still trails on newest features;
44
+ check the deployment feature matrix per feature, don't assume parity.
45
+ [nextjs.org/docs/app/guides/deploying-to-platforms]
46
+
47
+ ## Cloudflare Workers hard limits
48
+
49
+ - **Memory 128MB per isolate (hard), CPU 30s default / 5min max (configurable), 1000
50
+ subrequests per request (paid).** Heavy transforms (image processing, big parses)
51
+ belong in a container/worker tier, not a Worker. Workers Logs free tier: 200k
52
+ events/day, 3-day retention; automatic tracing starts billing 2026-10-01; OTLP export
53
+ needs Workers Paid. [developers.cloudflare.com/workers/platform/limits]
54
+
55
+ ## Better Auth (1.6.27, 2026-08-11)
56
+
57
+ - **1.7.0 is in RC** (rc.5 shipped 2026-08-11, same day as the pinned patch). Stay on
58
+ 1.6.x until 1.7 is stable; queued breaking changes include the MCP plugin restructure
59
+ (moves to `@better-auth/mcp`) and SAML IdP-initiated default-off. [github.com/better-auth]
60
+
61
+ - **The organizations plugin models teams, invitations, and custom RBAC end-to-end**
62
+ (`teams: { enabled: true }`, `invite-member` with `teamId`, `createAccessControl`) —
63
+ never hand-roll workspace/membership/groups schema. [better-auth.com/docs]
64
+ - **Better Auth ships an apiKey plugin** (docs/plugins/api-key — verified live
65
+ 2026-08-12; an older internal note claiming otherwise was wrong). Default to the plugin
66
+ for new projects; the flagship platform's native implementation (SHA-256 hash-stored,
67
+ raw shown once) is a recorded project decision, not the house default. The `bearer`
68
+ plugin covers token session transport (the mobile/Flutter mechanism).
69
+ - **`twoFactor` supports `allowPasswordless: true`** for users without password accounts
70
+ (passkey/OAuth/magic-link signups).
71
+
72
+ ## Agents & jobs
73
+
74
+ - **EVE (`eve` on npm, github.com/vercel/eve) is Vercel's durable-agent framework —
75
+ v0.33.2, still beta/pre-GA, shipping near-daily.** Filesystem-first agents; every
76
+ session a durable, resumable workflow. Exactly two production deploy shapes: on Vercel
77
+ as Vercel Functions with Fluid Compute (a recorded per-project exception to the hosting
78
+ default), or self-hosted as a long-running Node/OCI service beside Postgres. Never a
79
+ request-scoped/edge function (a Cloudflare Worker included) in either shape.
80
+ [vercel.com/docs/eve]
81
+ - **Self-hosted EVE durability (`@workflow/world-postgres`, stable 4.3.x) explicitly
82
+ requires a long-lived worker process — "not compatible with serverless platforms".**
83
+ Run EVE as its own Node/OCI service beside Postgres. The 5.0.0-beta channel exists;
84
+ don't pin it without a documented reason. Internally it uses graphile-worker — it is
85
+ not pg-boss and doesn't replace it. [workflow-sdk.dev/worlds/postgres]
86
+ - **pg-boss is at 12.x** — Postgres-native (`SKIP LOCKED`), no Redis. The right default
87
+ for simple background jobs/cron on this stack; BullMQ only when a genuinely complex job
88
+ graph (flows, dependencies, rate-limited pipelines) demands Redis. [npm: pg-boss]
89
+ - **trigger.dev v4 is Apache-2.0 and self-hostable free with unlimited runs** — the
90
+ credible escape hatch when a job needs multi-hour runtimes off-platform. [trigger.dev]
91
+
92
+ ## Databases & mobile
93
+
94
+ - **PlanetScale Postgres is built on Neki, not Vitess** — a newer product (GA 2025-09);
95
+ don't transfer Vitess/MySQL assumptions. No free tier (the free Hobby plan died April
96
+ 2024); Postgres pricing is SKU-based from PS-5 non-HA at $5/mo, HA from ~$15-50/mo.
97
+ ($39/mo figures seen elsewhere are the Vitess/MySQL PS-10 tier — a different product.)
98
+ [planetscale.com/pricing]
99
+ - **Flutter's default renderer is Impeller on iOS, Android, and macOS** — "disable
100
+ Impeller on Android" guidance is stale. [docs.flutter.dev]
101
+
102
+ ## Self-hosting
103
+
104
+ - **Coolify needs ~2GB RAM for its own control plane and requires active patching** —
105
+ two critical-CVE waves in 2026 alone (Jan: beta.445/451; Jun-Jul: CVE-2026-34047/49/50,
106
+ fixed in beta.471) — a recurring pattern, not a closed incident. Size Hetzner VMs
107
+ accordingly (CX22/4GB is the floor for Coolify + one small app); ~30 min/month real
108
+ maintenance, not zero. [coolify.io]
@@ -0,0 +1,91 @@
1
+ # Principles — how VegaStack decides
2
+
3
+ How MK actually makes architecture decisions, distilled from seven months of his sessions
4
+ and repos. Each rule carries its why — apply the reasoning, not just the rule.
5
+
6
+ ## Build lean first
7
+
8
+ One deployable until a concrete requirement forces a split. A single, properly structured
9
+ Next.js app owns the UI, RSC, route handlers, auth, and the REST/OpenAPI control plane — no
10
+ NestJS or Hono beside it, no speculative queue, cache, or worker. A notification sender is a
11
+ cron handler inside the app, not its own deployable. **Why:** agents habitually propose
12
+ services MK then has to strip out ("why do we still need workers like extra bloat or
13
+ maintenance surface?"). On a 3-4 person team, every moving part is real maintenance, and the
14
+ lean version is usually also the faster and more reliable one.
15
+
16
+ Lean-first governs the *count of moving parts*, not the rigor inside each part.
17
+ Correctness-critical logic — money, auth, tenancy, audit, secrets — always gets full rigor.
18
+
19
+ ## Every moving part names its trigger
20
+
21
+ Propose infrastructure only together with the trigger that justifies it, stated in the
22
+ recommendation: "a separate worker WHEN jobs exceed request timeouts", "a queue WHEN volume
23
+ makes inline processing lossy", "OpenBao WHEN self-hosting customer-managed secrets".
24
+ Provision only what the current build phase actually uses — infrastructure tracks real
25
+ usage, never anticipated usage. **Why:** MK stated "OpenBao mandatory in production" and
26
+ walked it back five days later ("some projects are just simple and straightforward").
27
+ Blanket mandates rot; triggers stay true as projects differ.
28
+
29
+ ## Pre-launch means delete, not migrate
30
+
31
+ Zero real users = no backward compatibility, no legacy shims, no deprecation windows, no
32
+ feature flags hiding unfinished work. Delete outright; reset the dev database rather than
33
+ writing migration chains. This is the DEFAULT — most VegaStack projects are pre-launch at
34
+ any given time. Expand/migrate/contract discipline begins when real users exist, not before.
35
+ **Why:** carrying compatibility for users who don't exist is pure bloat ("NO FEATURE FLAGS
36
+ PLEASE... i dont want any backwards compatibility as this is an unreleased app").
37
+ One exception: a versioned API contract consumed by a shipped mobile app counts as having
38
+ real users even while the web side iterates freely — app-store install lag keeps old
39
+ clients alive (mobile.md).
40
+
41
+ ## Reuse before you build new
42
+
43
+ Extend the existing table, service, or spine (ACL, change-log, outbox, realtime channel)
44
+ before creating a parallel one. When two components do the same job, merge them into one
45
+ canonical source. Promote a util to `/lib` the moment a second feature uses it. **Why:**
46
+ duplicated systems of record are the reference-architecture mistake MK explicitly engineers
47
+ against; two sources of the same truth always drift.
48
+
49
+ ## Enforce boundaries mechanically
50
+
51
+ Architectural boundaries that matter get a CI guard script that fails the build — monorepo
52
+ import direction (apps → packages, never the reverse; workers never import UI/React),
53
+ runtime gravity (below), server/client code separation. **Why:** convention alone was tried
54
+ and failed; a guard script is cheaper than re-reviewing the same violation forever.
55
+
56
+ ## Runtime gravity: long-running work never lives in the request tier
57
+
58
+ Anything that can run long, hold a connection, or outlive a request — agent execution, job
59
+ processing, media pipelines — runs in a separate worker/runner tier, never inside a route
60
+ handler or an OpenNext Worker. **Why:** request-scoped tiers have timeouts and body limits;
61
+ the reference codebase MK studied executed workflows inside Next.js handlers and it is the
62
+ single anti-pattern he cites most.
63
+
64
+ ## Effort scales with stakes, not habit
65
+
66
+ Security, auth, tenancy, money, and architecture foundations get generous, thorough,
67
+ adversarial treatment. Routine features on a small team get medium thoroughness — do a cheap
68
+ reconnaissance pass before committing to full-cost work, and don't build governance ceremony
69
+ a 3-4 person team will never exercise. **Why:** MK's own most recent self-correction — his
70
+ previous architecture skill "got too complicated" by applying flagship-platform rigor
71
+ everywhere.
72
+
73
+ ## Decisions are verified, recorded, and reversible for a reason
74
+
75
+ - Resolve uncertainty with evidence, never with the safer-sounding guess: check the live
76
+ official docs (current year), verify the claimed constraint, then decide. MK refused to
77
+ accept an unverified "Better Auth forces text UUID columns" claim — it was false.
78
+ - Present decisions as 2-3 options with a clear recommendation and the tradeoff that
79
+ matters, then record what was chosen and why (an ADR or one dated ledger line).
80
+ - MK reverses when: a verified assumption proves false · added cleverness regresses UX ·
81
+ a heavyweight mandate meets a simple project · his own tooling over-complicates. He
82
+ reverses toward less machinery on low stakes and toward more rigor only when a concrete
83
+ bug or vulnerability is found. Anticipate this: don't defend machinery he'd delete.
84
+
85
+ ## Context gates rigor — ask, don't assume
86
+
87
+ Rigor flexes on facts, not labels: pre-launch or live · internal, client, or OSS ·
88
+ self-hosted or managed · handles money/PII or not · has real users or not. These live in
89
+ `.vegastack/arch.md`. Client work gets the same approval gates and honesty as internal work
90
+ — if anything, more documentation, never less. When two recorded decisions conflict or the
91
+ profile can't answer, ask MK with a recommendation instead of assuming.
@@ -0,0 +1,37 @@
1
+ # Project profile — `.vegastack/arch.md`
2
+
3
+ The per-project memory that stops every session from re-deriving the same facts. It is a
4
+ head start, never the source of truth: the repository wins every disagreement.
5
+
6
+ ## First run in a project
7
+
8
+ If `.vegastack/arch.md` does not exist and the task is architectural:
9
+
10
+ 1. First infer what you can from the repo — package.json/lockfile (runtime), wrangler
11
+ files (Cloudflare; a `d1_databases` binding with no Postgres driver = the D1-only
12
+ product class), Dockerfiles/compose (self-managed), drizzle config (database),
13
+ better-auth usage, `@aws-sdk/client-s3`/R2 bindings (storage), pg-boss dependency
14
+ (jobs), `eve`/`ai` packages (agents vs plain AI features), pubspec.yaml (mobile).
15
+ 2. Ask MK or the team member only what the repo can't answer, in one short message:
16
+ - Where does this deploy? (Cloudflare Workers via OpenNext · self-managed server ·
17
+ both · exception: Vercel)
18
+ - Stage and kind? (pre-launch or live · internal, client, or oss)
19
+ - Anything non-default? (mobile app, agents, separate workers, unusual services)
20
+ 3. Write `.vegastack/arch.md` from [the template](../assets/arch-template.md), show it,
21
+ and confirm before relying on it. Creating the file needs the same write authorization
22
+ as any other file.
23
+
24
+ Never create the file during a purely read-only task or an explanation — suggest it instead.
25
+
26
+ ## Every later run
27
+
28
+ - Read the file, then trust the repo over it. If the repo disagrees (the file says bun but
29
+ the lockfile is pnpm-lock.yaml; a wrangler.jsonc appeared; a mobile/ directory exists),
30
+ say so and propose the exact one-line file update. Never silently follow a stale profile,
31
+ and never silently rewrite it either.
32
+ - Decisions and their dates belong in the `notes:` lines — one line per decision ("2026-08:
33
+ DO for realtime only, dropped for chat — SSE+Postgres instead"). This is the project's
34
+ decision ledger; keep entries short and dated.
35
+ - If the file records something that contradicts this skill's defaults, the file wins for
36
+ that project — it is a recorded decision. Report it as accepted risk only if it crosses
37
+ a red line.
@@ -0,0 +1,97 @@
1
+ # Security & auth
2
+
3
+ Auth, tenancy-isolation, and secrets work is the highest-rigor tier: extra precision on
4
+ every change, and a focused security audit after any auth-adjacent change before it's done.
5
+
6
+ ## Authentication (Better Auth, always)
7
+
8
+ - Email/password + Google sign-in is the default configuration; magic link and email OTP
9
+ as flows demand; 2FA TOTP when the product warrants (note `allowPasswordless: true` for
10
+ passkey/OAuth-only users). Follow Better Auth's documented APIs — never hand-roll session
11
+ or cache invalidation beside them.
12
+ - The organizations plugin (with teams enabled) owns orgs/workspaces/teams/invitations —
13
+ organization maps to workspace; "user groups" of any kind are Better Auth teams. Use the
14
+ SSO plugin for SAML/OIDC when enterprise auth arrives — don't build protocol code.
15
+ - Mobile uses the bearer plugin (token from `set-auth-token`, stored in secure storage) —
16
+ same auth instance, same Postgres, as the web app.
17
+ - Sessions: rolling expiry, Postgres-authoritative. Do not enable cookie-cache-style
18
+ session shortcuts without checking Better Auth's current issues — a cookieCache bug
19
+ once caused silent 5-minute logouts in production. Session revocation ("sign out
20
+ everywhere", admin-initiated) goes through Better Auth's session-list/revoke APIs
21
+ server-side — never a hand-rolled cache-invalidation scheme beside them.
22
+ - Google OAuth footgun: set `baseURL` explicitly in production config — an unset or wrong
23
+ value silently targets localhost and fails Google's exact-match redirect-URI check.
24
+ - API keys: use Better Auth's apiKey plugin by default. Whatever implements them, the
25
+ invariants hold: hash-stored with a recognizable prefix, raw value shown exactly once
26
+ and never cached or logged again, constant-time compare on verify.
27
+
28
+ ## Authorization
29
+
30
+ - Middleware/proxy is never the boundary (CVE-2025-29927 class). The boundary is a
31
+ server-only data-access layer — `requireSession()`/`requireOrgRole()`-style helpers,
32
+ re-checked per resource, on every route, auth before body parse.
33
+ - Every check fails closed: a policy-engine error, throw, or unmatched rule resolves to
34
+ deny, and the deny is still audited. No `DISABLE_AUTH`/`BILLING_ENABLED=false` style
35
+ escape hatches, ever. Dev-only conveniences (e.g. skipping email verification) are OK
36
+ only when explicitly gated to non-production with zero prod behavior change.
37
+ - Role models stay small — Owner/Admin/Member covers most products. A policy engine
38
+ (Cedar-class ABAC) needs a named trigger — fine-grained multi-principal authorization
39
+ over agent/tool calls at platform scale; today only the flagship platform has earned
40
+ it. Any other project proposing one: present the trigger and ask MK.
41
+ - Tenant identity always derives from the authenticated principal — never from a
42
+ client-supplied workspace/org ID (a trusted `?workspaceId=` param caused a real
43
+ cross-tenant IDOR). Cross-tenant lookups return 404, never 403 — no existence oracle.
44
+ - If ALL UI consumers of a route sit inside the authenticated app shell, the route
45
+ requires auth even when its data "seems public" — trace actual callers before accepting
46
+ "intentionally public".
47
+ - Tenancy at the data layer: RLS ENABLE+FORCE plus explicit scoping — see data.md.
48
+
49
+ ## Secrets
50
+
51
+ - No plaintext secrets anywhere: not in code, config files, wrangler.jsonc, generated
52
+ output, logs, audit records (redact to a short prefix), agent state, or JSONB columns.
53
+ Cloudflare Worker secrets and GitHub secrets are the storage; a credential broker
54
+ (envelope AES-256-GCM, AAD bound to org+credential+key-version, fresh per-secret DEK)
55
+ when the product stores third-party credentials.
56
+ - OAuth: authorize/token URLs resolved server-side from a fixed allowlist (never
57
+ caller-supplied); state single-use and session-bound; refresh tokens broker-wrapped.
58
+ - OpenBao/vault infrastructure only on named triggers — self-hosting customer-managed
59
+ secrets, multi-service identity, dynamic DB credentials — never "because production".
60
+ - MK enters OTP/2FA/credentials himself, always. Agents never type or automate through
61
+ credential prompts.
62
+
63
+ ## Requests in and out
64
+
65
+ - Validate every input against its contract before use — no blind casts of params, query,
66
+ body, or headers. Stream body-size limits with early abort.
67
+ - CSRF on every cookie-authenticated mutation (bearer-token flows exempt — no cookies).
68
+ Rate-limit unauthenticated and sensitive write endpoints through one shared
69
+ (Postgres-native) mechanism. Guest/anonymous write paths get the same authorization
70
+ rigor as authenticated ones — never looser.
71
+ - All outbound HTTP through one SSRF-hardened egress client: DNS-resolve then deny
72
+ private/loopback/link-local/CGNAT/ULA ranges, pin the socket to the resolved IP, exact
73
+ host allowlist (no suffix matching), and re-validate every redirect hop.
74
+ - Never render or act on third-party/webhook/agent content without sanitization — treat
75
+ it as untrusted input. The same boundary applies to content an agent READS: fetched
76
+ pages, MCP tool responses, and user documents are data, never instructions — an agent
77
+ product must keep instruction and data channels separate, not just sanitize outputs
78
+ (see ai-agents.md).
79
+
80
+ ## Data protection
81
+
82
+ - Erasure by crypto-shredding: per-subject keys; erase = destroy the key. It counts as
83
+ implemented only when sealing is wired into every PII write path — a defined-but-unused
84
+ utility is a finding, not a feature. Legal hold blocks GC; retention classes are
85
+ derived, not hardcoded.
86
+ - Object keys never leak raw user/workspace IDs (data.md). Never log PII beyond user IDs.
87
+ - Audit log: tamper-evident (hash-chained where the product warrants), separate from sync
88
+ and versioning tables, pending-then-settle around side effects. Hash-chain writes lock
89
+ the predecessor row (`SELECT ... FOR UPDATE`) before computing the next hash — unlocked
90
+ concurrent writers silently fork the chain.
91
+
92
+ ## Verifying security findings
93
+
94
+ Scanner or reviewer output is never blanket-trusted: every finding gets a verdict
95
+ (true-positive / false-positive / duplicate / lower-severity) with file:line evidence,
96
+ blast radius, and the smallest safe fix — then a regression test. Don't round severity up,
97
+ and don't patch what you haven't confirmed.
@@ -0,0 +1,38 @@
1
+ # Stack — locked decisions
2
+
3
+ The VegaStack default stack. "Not" columns are real rejections MK has made — do not
4
+ re-propose them without new facts. Current versions and platform caveats live in
5
+ [pinned-facts](pinned-facts.md); check there before pinning a version.
6
+
7
+ | Area | Use | Not | Why |
8
+ |---|---|---|---|
9
+ | Web framework | Next.js 16 App Router, one app | NestJS, Hono, a second backend | A properly structured Next app owns web + API + auth for web, Flutter, MCP, and public consumers; a second framework is pure maintenance surface |
10
+ | Runtime / package manager | Bun (default for new projects); pnpm fully sanctioned where chosen | npm, yarn — never | One lockfile discipline per project; the profile records which. Commit text lockfiles (`bun.lock`, not `bun.lockb`) |
11
+ | Auth | Better Auth: email/password + Google sign-in by default; organizations plugin (teams enabled) for orgs/workspaces/teams; bearer plugin for mobile; apiKey plugin for API keys | Hand-rolled auth, custom user-groups schema, Auth0/Clerk | Owner-stated standing rule. Organization maps to workspace (`modelName: "workspace"` pattern); teams = Better Auth teams; prefer the shipped plugins over native builds unless a project records why |
12
+ | Database | PostgreSQL, always self-managed by us: PlanetScale Postgres server or self-hosted (Hetzner or similar). PG 17 behind Hyperdrive; 17/18 otherwise. D1-only is a recorded exception for the minimal Cloudflare-native product class (vegastack-pages/vegafactory precedent, locked 2026-05-20) — check `.vegastack/arch.md` before assuming Postgres | Neon (never), D1 as a secondary store beside Postgres, MySQL | "We don't use neon at all." One datastore per product; Hyperdrive caps at PG 17.x (see pinned-facts). D1's sanctioned sidecar case: a Worker-scoped idempotency table for Stripe webhooks — Postgres still owns the ledger |
13
+ | ORM | Drizzle + drizzle-kit, single `postgres-js` driver | Prisma | House standard across every repo since Feb 2026 |
14
+ | DB from Workers | Hyperdrive binding, per-request client (`prepare: false, max: 1`, request-scoped) | Global pools, TCP clients (ioredis) in Workers | workerd forbids I/O across requests; a module-level pool is a bug, not a style choice |
15
+ | Storage | Cloudflare R2 (S3-compatible API), presigned URLs, short-lived scoped access | S3 + CloudFront by reflex | R2 egress is $0 at any scale — the cost problem S3+CDN solves doesn't exist here. For licensed self-hosted deployments, keep the S3 protocol boundary so any S3 provider or MinIO works |
16
+ | Cache / Redis | None by default. Rate limiting and caching Postgres-native; Workers KV only with a named trigger (e.g. read-mostly config/session cache at request volumes where a Postgres round-trip measurably hurts — as in the recorded auth-cache migration); a Redis-class store never correctness-bearing | Upstash Redis (migrated off), Redis "because caching" | "No Redis in P1" — a cache layer is a moving part; Postgres already exists. Never cache authorization/role data aggressively |
17
+ | Jobs / cron | pg-boss on the existing Postgres, dispatcher-only — lease/heartbeat/retry state of authority lives in our own tables. Cron parsing/description: `croner` (DST/IANA-aware) + `cronstrue` (human-readable) | BullMQ+Redis, Temporal, CF Queues by default; `node-cron`, `cron-parser` | Jobs are simple; Postgres is already there. Owning durability state keeps the queue library swappable; croner/cronstrue are the battle-tested cron pair (a cron-parser swap was made and corrected once already) |
18
+ | Agent execution | EVE (Vercel's `eve`, beta): on Vercel as Functions with Fluid Compute (recorded per-project exception), or self-hosted as its own long-running Node/OCI service with `@workflow/world-postgres` | EVE inside an OpenNext Worker or any request-scoped/edge function | EVE's Postgres world explicitly requires a long-lived worker process — "not compatible with serverless platforms". EVE owns agent sessions; pg-boss owns generic jobs — complementary, never conflated |
19
+ | AI calls | AI SDK v7 (`ai@^7`) behind a thin adapter; Anthropic default provider; Cloudflare AI Gateway for routing/telemetry when on Cloudflare | Hardcoded model IDs scattered in code, per-provider SDKs everywhere | Adapter keeps providers swappable; the gateway centralizes cost/telemetry without building it |
20
+ | Design system | Consume `@vegastack/design` + `@vegastack/ui` (Base UI primitives, semantic tokens) | Creating/modifying components upstream, raw shadcn edits, Radix for new work | Consume, don't extend — upstream changes are MK's deliberate decision. Base UI locked over Radix 2026-07 |
21
+ | Frontend state | Server state via RSC + TanStack Query; URL state via nuqs; ephemeral UI state via Zustand | Persisting remote/tenant data client-side (IndexedDB/local-first) for multi-tenant SaaS | Governance: tenant data never rests on the client. Local-first only for a confirmed single-tenant/offline product — ask first |
22
+ | Realtime | SSE tailing an event log first; Durable Objects (SQLite, WebSocket hibernation) when on Cloudflare and bidirectional state is real. One DO per collaboration scope (a `WorkspaceHub` for presence/signals, a per-document `PageSync` for edit traffic) — never one monolithic DO | socket.io + Redis pub/sub, Ably, Pusher | SSE covers most "live" needs with zero new services; hibernating DOs bill ~nothing while idle. Third-party realtime vendors were migrated off |
23
+ | Collaborative editing | Tiptap editor (markdown as source of truth), Yjs CRDT sync via `y-partyserver` inside the document DO; server-side sanitization/versioning still applies to every CRDT write | CodeMirror (abandoned 2026-05-21), ElectricSQL (removed), RxDB (reversed to plain Dexie where local cache is needed) | Locked through real reversals; CRDT must never become an XSS/version/audit bypass |
24
+ | Analytics | Self-hosted Plausible (`pb.vegastack.com`), proxied via `next-plausible` where applicable | Google Analytics, Vercel Analytics, PostHog by default | Self-hosted, privacy-clean, already running — recurs across 5 projects |
25
+ | Hosting | Cloudflare Workers via OpenNext, or self-managed servers (Docker; Coolify for push-to-deploy). Both recorded in the profile | Vercel as a default (allowed only by explicit per-project exception, recorded); a parallel Vercel path once committed to Cloudflare | Cost and egress economics favor Cloudflare/self-host; split deploy paths drift. EVE-hosted workloads are a legitimate Vercel exception |
26
+ | Email | AWS SES (behind an adapter); handle bounces/complaints via the SNS-webhook pattern into a suppression list | Per-vendor SDK sprawl, sending to suppressed addresses | Cheap, boring, already proven in-house; unhandled bounces poison sender reputation |
27
+ | Payments | Stripe; webhook intake isolated (own worker or route) with idempotent event handling | Building billing logic inside request handlers | Money paths get the full rigor tier: idempotency keys, event dedupe, DLQ |
28
+ | Monorepo | Turborepo + workspaces (Bun or pnpm) when there is more than one package; apps → packages only, enforced by a boundary check | Deep relative cross-package imports, packages importing apps | Import direction is a guard script, not a convention |
29
+ | i18n | next-intl, `localePrefix: 'as-needed'`; no hardcoded user-facing strings | Ad-hoc string tables | Already the proven pattern; English-only today but scaffolded |
30
+ | APIs | Contract-first: zod schemas → OpenAPI 3.1; auth before parse; cursor pagination on every list; RFC 9457 problem-details errors | Route-local validation, raw `request.json()`, unbounded lists | One contract feeds web, Flutter, MCP, and public consumers; sanitize responses (never return secrets/credential refs) |
31
+
32
+ ## Choosing between the two hosting targets
33
+
34
+ Cloudflare (OpenNext) when: public web product, global latency matters, R2/DO/Queues fit,
35
+ cost-per-request dominates. Self-managed (Docker/Hetzner) when: self-hosting is a product
36
+ requirement (licensed/enterprise), the workload needs long-lived processes (EVE, heavy
37
+ workers), or platform independence is worth ~30 min/month of ops. Many products use both:
38
+ OpenNext app on Cloudflare + a long-running worker container beside the database.