From eb7affc4c8b3b068b5e91ab446b11a277918699a Mon Sep 17 00:00:00 2001 From: Aneeb Baig Date: Fri, 3 Jul 2026 02:24:21 +0500 Subject: [PATCH] feat: add app-starter plugin (Next.js, Flutter, FastAPI bootstrap skills) --- .claude-plugin/marketplace.json | 21 +++- .../app-starter/.claude-plugin/plugin.json | 20 ++++ .../app-starter/skills/fastapi-app/SKILL.md | 87 ++++++++++++++ .../fastapi-app/references/best-practices.md | 82 +++++++++++++ .../fastapi-app/references/quality-gates.md | 68 +++++++++++ .../skills/fastapi-app/references/stack.md | 45 ++++++++ .../fastapi-app/references/structure.md | 51 +++++++++ .../fastapi-app/scripts/check-latest.sh | 34 ++++++ .../app-starter/skills/flutter-app/SKILL.md | 92 +++++++++++++++ .../flutter-app/references/architecture.md | 108 ++++++++++++++++++ .../flutter-app/references/best-practices.md | 87 ++++++++++++++ .../flutter-app/references/quality-gates.md | 63 ++++++++++ .../skills/flutter-app/references/stack.md | 57 +++++++++ .../flutter-app/scripts/check-latest.sh | 39 +++++++ .../app-starter/skills/nextjs-app/SKILL.md | 88 ++++++++++++++ .../nextjs-app/references/quality-gates.md | 57 +++++++++ .../skills/nextjs-app/references/stack.md | 56 +++++++++ .../skills/nextjs-app/references/structure.md | 49 ++++++++ .../skills/nextjs-app/references/variants.md | 43 +++++++ .../skills/nextjs-app/scripts/check-latest.sh | 32 ++++++ .../skills/shared/docs-and-context.md | 43 +++++++ .../app-starter/skills/shared/git-and-ci.md | 50 ++++++++ .../app-starter/skills/shared/hardening.md | 63 ++++++++++ .../app-starter/skills/shared/house-rules.md | 72 ++++++++++++ .../skills/shared/no-ai-attribution.md | 64 +++++++++++ .../skills/shared/open-source-docs.md | 43 +++++++ 26 files changed, 1513 insertions(+), 1 deletion(-) create mode 100644 plugins/app-starter/.claude-plugin/plugin.json create mode 100644 plugins/app-starter/skills/fastapi-app/SKILL.md create mode 100644 plugins/app-starter/skills/fastapi-app/references/best-practices.md create mode 100644 plugins/app-starter/skills/fastapi-app/references/quality-gates.md create mode 100644 plugins/app-starter/skills/fastapi-app/references/stack.md create mode 100644 plugins/app-starter/skills/fastapi-app/references/structure.md create mode 100755 plugins/app-starter/skills/fastapi-app/scripts/check-latest.sh create mode 100644 plugins/app-starter/skills/flutter-app/SKILL.md create mode 100644 plugins/app-starter/skills/flutter-app/references/architecture.md create mode 100644 plugins/app-starter/skills/flutter-app/references/best-practices.md create mode 100644 plugins/app-starter/skills/flutter-app/references/quality-gates.md create mode 100644 plugins/app-starter/skills/flutter-app/references/stack.md create mode 100755 plugins/app-starter/skills/flutter-app/scripts/check-latest.sh create mode 100644 plugins/app-starter/skills/nextjs-app/SKILL.md create mode 100644 plugins/app-starter/skills/nextjs-app/references/quality-gates.md create mode 100644 plugins/app-starter/skills/nextjs-app/references/stack.md create mode 100644 plugins/app-starter/skills/nextjs-app/references/structure.md create mode 100644 plugins/app-starter/skills/nextjs-app/references/variants.md create mode 100755 plugins/app-starter/skills/nextjs-app/scripts/check-latest.sh create mode 100644 plugins/app-starter/skills/shared/docs-and-context.md create mode 100644 plugins/app-starter/skills/shared/git-and-ci.md create mode 100644 plugins/app-starter/skills/shared/hardening.md create mode 100644 plugins/app-starter/skills/shared/house-rules.md create mode 100644 plugins/app-starter/skills/shared/no-ai-attribution.md create mode 100644 plugins/app-starter/skills/shared/open-source-docs.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 6f29b6b..262c3c3 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1670,6 +1670,25 @@ "security", "compliance" ] + }, + { + "name": "app-starter", + "source": "./plugins/app-starter", + "description": "Bootstrap new Next.js, Flutter, and FastAPI apps with current packages, no deprecated APIs, and a consistent house style. Ships skills nextjs-app, flutter-app, and fastapi-app.", + "version": "0.2.0", + "author": { + "name": "Aneeb Baig" + }, + "category": "Development Engineering", + "homepage": "https://github.com/aneebbaig/app-starter-skills", + "keywords": [ + "nextjs", + "flutter", + "fastapi", + "scaffold", + "starter", + "bootstrap" + ] } ] -} \ No newline at end of file +} diff --git a/plugins/app-starter/.claude-plugin/plugin.json b/plugins/app-starter/.claude-plugin/plugin.json new file mode 100644 index 0000000..f786157 --- /dev/null +++ b/plugins/app-starter/.claude-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "name": "app-starter", + "description": "Bootstrap new Next.js, Flutter, and FastAPI apps with current packages, no deprecated APIs, and a consistent house style. Ships skills nextjs-app, flutter-app, and fastapi-app.", + "version": "0.2.0", + "author": { + "name": "Aneeb Baig", + "url": "https://github.com/aneebbaig" + }, + "homepage": "https://github.com/aneebbaig/app-starter-skills", + "repository": "https://github.com/aneebbaig/app-starter-skills", + "license": "MIT", + "keywords": [ + "nextjs", + "flutter", + "fastapi", + "scaffold", + "starter", + "bootstrap" + ] +} diff --git a/plugins/app-starter/skills/fastapi-app/SKILL.md b/plugins/app-starter/skills/fastapi-app/SKILL.md new file mode 100644 index 0000000..1116e80 --- /dev/null +++ b/plugins/app-starter/skills/fastapi-app/SKILL.md @@ -0,0 +1,87 @@ +--- +name: fastapi-app +description: Bootstrap a new FastAPI backend with async SQLAlchemy 2.0, asyncpg, Alembic, Pydantic v2, and no deprecated APIs. Use when the user wants to start, scaffold, or set up a new FastAPI service, a Python REST API, an async backend, or asks to "create a new fastapi app" or "new python backend". Handles JWT auth, layered app structure, Docker + Postgres, and Vercel or container deploy. +--- + +# fastapi-app + +Bootstrap a new FastAPI backend the way this owner builds them: async SQLAlchemy +2.0 with asyncpg, Alembic migrations, Pydantic v2 settings, a layered structure +(routers, services, models, schemas), JWT auth, and the house git and CI +workflow. Deployable to a container or Vercel. + +First read the shared rules (they override anything you remember): +`../shared/house-rules.md`, `../shared/no-ai-attribution.md`, +`../shared/git-and-ci.md`, `../shared/docs-and-context.md`, +`../shared/hardening.md`, and (for public repos) `../shared/open-source-docs.md`. + +## Step 0. Get the brief, then ask the variant questions (hard stop) + +This is a hard stop. Do not run any scaffolding command until the user has +answered. + +First, get the project brief: one paragraph on what the service does, its main +resources and endpoints, who calls it, and any hard constraints. If the user has +not given one, ask for it. The brief drives naming, the domain modules, and the +data model. + +Then ask the variant questions. If a choice has multiple options, ask; do not +assume. Ask in one batch, then proceed. + +1. Repo visibility: private, open-source, or private-plus-open-source. +2. Auth: JWT (python-jose or PyJWT), OAuth (Google), API-key, or none yet. +3. Database: Postgres via async SQLAlchemy + asyncpg (default), or none yet. +4. Dependency tooling: `uv` (default, fast) or `pip` + `requirements.txt`. +5. Admin UI: SQLAdmin, or none. +6. Deploy target: Docker container (default) or Vercel serverless. + +If the user already answered some, do not re-ask. + +## Step 1. Verify environment and current versions + +- Check Python (`python3 --version`, want a current supported 3.x). +- Run `scripts/check-latest.sh` for current stable versions from PyPI. Pin those, + not versions from memory (`../shared/house-rules.md` rule 2). +- Pull current FastAPI, SQLAlchemy 2.0, and Pydantic v2 docs via Context7 before + writing code (`../shared/docs-and-context.md`). SQLAlchemy 2.0 async and + Pydantic v2 both broke v1 patterns; do not write v1-era code from memory. + +## Step 2. Scaffold the project + +Create a virtualenv and the layout from `references/structure.md`. With `uv`: + +``` +uv init && cd +uv add fastapi "uvicorn[standard]" "sqlalchemy[asyncio]" asyncpg alembic \ + pydantic-settings python-jose[cryptography] httpx python-multipart +uv add --dev ruff pytest pytest-asyncio +``` + +With pip, install the same set and freeze into `requirements.txt`. Let the tool +resolve current versions; do not force numbers you remember. + +## Step 3. Apply structure and conventions + +- Layered app structure, async DB session, dependency-injected DB, settings, JWT + auth: `references/structure.md`. +- Best practices, scalable domain-modular architecture, and nothing hardcoded: + `references/best-practices.md`. +- Dependency set and version-boundary notes: `references/stack.md`. +- Production hardening (docs and schema disabled or gated in prod, generic error + bodies, debug off, CORS locked): `../shared/hardening.md`. + +## Step 4. Git, CI, docs, security + +- Git branch model, conventional commits, auto-merge: `../shared/git-and-ci.md`. +- CI (ruff + pytest), Docker, migrations: `references/quality-gates.md`. +- Gitignore `.env*` and any service-account JSON. Provide `.env.example`. + Settings load from env through `pydantic-settings`, never hardcoded. +- Add `docs/` and a README. For a public repo, ship the full open-source docs set + per `../shared/open-source-docs.md` and run the open-source hard gate in + `../shared/no-ai-attribution.md` before the first push. + +## Step 5. Verify before declaring done + +Run the gates in `references/quality-gates.md`: `ruff check`, `pytest`, the app +imports and starts, `/health` responds, and Alembic can generate a revision. +Report real results. diff --git a/plugins/app-starter/skills/fastapi-app/references/best-practices.md b/plugins/app-starter/skills/fastapi-app/references/best-practices.md new file mode 100644 index 0000000..368be37 --- /dev/null +++ b/plugins/app-starter/skills/fastapi-app/references/best-practices.md @@ -0,0 +1,82 @@ +# FastAPI best practices and scalable architecture + +Read before writing endpoints. Confirm current FastAPI, SQLAlchemy 2.0, and +Pydantic v2 syntax via Context7 first; this file describes patterns by intent, +not by a pinned version. + +## Layered, scalable structure + +Start with the layered layout in `structure.md`. As the service grows, scale it +into a versioned, domain-modular shape rather than one flat folder: + +``` +app/ + main.py create_app(): middleware, exception handlers, router mount + api/ + v1/ + router.py aggregates the v1 resource routers + .py thin route handlers per resource + deps.py shared dependencies (get_db, get_current_user, pagination) + core/ + config.py Settings via pydantic-settings + security.py JWT, hashing + database.py async engine, sessionmaker, get_db + logging.py structured logging setup + domain/ + / + models.py SQLAlchemy 2.0 Mapped models + schemas.py Pydantic v2 request and response models + service.py business logic, composes repositories + repository.py data access, the only place that runs queries + workers/ background jobs (optional: Celery, arq, or TaskiQ) + tests/ +``` + +Version the public API from day one (`/api/v1`). Group by domain, not by +technical layer, once you pass a handful of resources. This is a modular monolith: +one deployable, clean internal seams, ready to split later. + +## Do + +- Keep route handlers thin: validate input with a schema, call a service, return + a response model. No business logic or SQL in the handler. +- One layer per job: handler -> service -> repository -> model. A layer only talks + to the one below it. +- Use async end to end: async engine, async session, `await` on all DB calls, and + `async def` handlers for anything that touches IO. +- Inject the DB session and the current user as dependencies (`Depends`). Never + build a session inside a handler. +- Define response models that exclude sensitive fields. Never return password + hashes, tokens, or internal ids you do not mean to expose. +- Validate and constrain input with Pydantic (types, bounds, enums). Reject bad + input at the edge. +- Paginate list endpoints. Never return an unbounded collection. +- Handle errors with typed exceptions and registered exception handlers that + return a clean, generic error body. +- Configure Alembic against the async engine URL from settings. Review every + autogenerated migration before applying. + +## Do not + +- Do not mix sync and async DB access. Pick async. +- Do not use the SQLAlchemy 1.x Query API (`session.query(...)`). Use `select()` + with an async session. +- Do not write Pydantic v1 patterns (`orm_mode`, `@validator`). Use + `from_attributes` and `@field_validator`. +- Do not put queries in services or handlers. Queries live in repositories. +- Do not leak `SECRET_KEY`, DB URLs, or provider keys into responses, logs, or + the OpenAPI schema. +- Do not catch broadly and swallow. Let typed exceptions bubble to the handlers. +- Do not trust client input for authorization. Re-check ownership on the server + for every mutating call. + +## Nothing hardcoded + +- All config comes from `pydantic-settings` reading env: DB URL, secret key, + token lifetimes, CORS origins, external URLs, feature flags. Provide + `.env.example` with every key. +- Fixed choices are Python enums, not string literals sprinkled across the code. +- Route path prefixes, pagination defaults, and limits are named constants, not + magic numbers inline. +- If you are about to type a literal secret, URL, or tunable number into a + handler or service, move it into settings or a constants module first. diff --git a/plugins/app-starter/skills/fastapi-app/references/quality-gates.md b/plugins/app-starter/skills/fastapi-app/references/quality-gates.md new file mode 100644 index 0000000..7a35516 --- /dev/null +++ b/plugins/app-starter/skills/fastapi-app/references/quality-gates.md @@ -0,0 +1,68 @@ +# FastAPI quality gates, CI, and deploy + +## Local gates (run before every commit and in CI) + +``` +ruff check . +ruff format --check . +pytest +python -c "from app.main import app" # imports cleanly +``` + +Run the app locally and confirm `/health` responds and `/docs` renders the +OpenAPI UI. + +## CI workflow + +`.github/workflows/ci.yml`, a job on PRs into `develop` and `main`: + +```yaml +name: CI +on: + pull_request: + branches: [develop, main] +jobs: + build: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16 + env: + POSTGRES_PASSWORD: postgres + ports: ["5432:5432"] + options: >- + --health-cmd pg_isready --health-interval 10s + --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + - run: pip install -r requirements.txt + - run: ruff check . + - run: pytest + env: + DATABASE_URL: postgresql+asyncpg://postgres:postgres@localhost:5432/postgres +``` + +Pin the Python version to the one you install and the action majors to current. +Set branch protection to require the `build` job, then use +`gh pr merge --squash --auto`. + +## Docker + +- `Dockerfile` on a slim Python base, install deps, run + `uvicorn app.main:app --host 0.0.0.0 --port 8000`. +- `docker-compose.yml` with the app plus Postgres for local dev. + +## Vercel (serverless option) + +- A `vercel.json` routing all paths to the ASGI app. Note serverless cold starts + and connection limits; use a pooled or serverless Postgres and keep the async + engine pool small. + +## Verify before declaring done + +`ruff check` clean, `pytest` green, the app imports and starts, `/health` +responds, and `alembic revision --autogenerate` produces a sane migration. +Report real results. diff --git a/plugins/app-starter/skills/fastapi-app/references/stack.md b/plugins/app-starter/skills/fastapi-app/references/stack.md new file mode 100644 index 0000000..a55c82b --- /dev/null +++ b/plugins/app-starter/skills/fastapi-app/references/stack.md @@ -0,0 +1,45 @@ +# FastAPI stack + +Default dependency set from the owner's shipped backend. Pin to the live stable +versions from `scripts/check-latest.sh`, not the numbers here. + +## Core + +- `fastapi` and `uvicorn[standard]` (ASGI server, standard extras for reload and + websockets). +- `pydantic` v2 and `pydantic-settings` for typed settings loaded from env. +- `python-multipart` for form and file uploads. + +## Database (default: async Postgres) + +- `sqlalchemy[asyncio]` on the 2.0 line, with `asyncpg` as the async driver. +- `alembic` for migrations. +- Use the 2.0 style: `async_engine`, `async_sessionmaker`, `Mapped[...]` typed + models, and `select()` statements. Do not write 1.x Query API or the old + `declarative_base` patterns from memory. + +## Auth + +- JWT via `python-jose[cryptography]` or `PyJWT`. Hash passwords with `bcrypt` + or `passlib[bcrypt]`. +- OAuth (Google) via `google-auth` when the app signs users in with Google. + +## Optional + +- `sqladmin` for a quick admin UI over the SQLAlchemy models. +- `httpx` for outbound HTTP (also the test client transport). + +## Tooling + +- `ruff` for lint and format (replaces flake8 + black + isort). +- `pytest` + `pytest-asyncio` for async tests. +- `uv` for dependency management and lockfile, or `pip` + `requirements.txt`. + +## Version-boundary notes + +- SQLAlchemy 2.0 is a hard break from 1.4. If you find yourself writing + `session.query(...)`, stop and use `select()` with an async session. +- Pydantic v2 changed validators, config, and serialization. `orm_mode` is now + `from_attributes`; `@validator` is now `@field_validator`. Confirm current + syntax in the Pydantic v2 docs. +- Do not mix sync and async DB sessions. Pick async end to end. diff --git a/plugins/app-starter/skills/fastapi-app/references/structure.md b/plugins/app-starter/skills/fastapi-app/references/structure.md new file mode 100644 index 0000000..a09d16d --- /dev/null +++ b/plugins/app-starter/skills/fastapi-app/references/structure.md @@ -0,0 +1,51 @@ +# FastAPI project structure + +Layered structure, matching the owner's shipped backend. + +``` +/ + app/ + main.py create_app(), router registration, middleware, /health + core/ + config.py Settings (pydantic-settings), reads env + security.py JWT encode/decode, password hashing + database.py async engine, async_sessionmaker, get_db dependency + routers/ one module per resource, thin: parse, call service, return + services/ business logic, the only layer that composes repositories + models/ SQLAlchemy 2.0 Mapped models + schemas/ Pydantic v2 request and response models + utils/ helpers + alembic/ migration env and versions + alembic.ini + scripts/ seed and ops scripts + tests/ + Dockerfile + docker-compose.yml # app + postgres for local dev + .env.example + requirements.txt # or pyproject.toml + uv.lock +``` + +## Patterns + +- Routers are thin. They validate input via a `schemas/` model, call a service, + and return a response model. No business logic or raw SQL in routers. +- The DB session is a dependency: + ```python + async def get_db() -> AsyncIterator[AsyncSession]: + async with async_session() as session: + yield session + ``` + Inject it with `db: AsyncSession = Depends(get_db)`. +- Settings come from `pydantic-settings` reading env. Never hardcode secrets or + URLs. Provide `.env.example` with every key. +- Auth: a `get_current_user` dependency decodes the JWT and loads the user. + Protected routes depend on it. +- Response models exclude sensitive fields. Never return password hashes or raw + tokens in a response schema. +- CORS, request logging, and error handlers are registered in `create_app()`. + +## Migrations + +- Configure Alembic to use the async engine URL from settings. +- Autogenerate after model changes: `alembic revision --autogenerate -m "..."`, + then review the generated migration before applying. Never edit the DB by hand. diff --git a/plugins/app-starter/skills/fastapi-app/scripts/check-latest.sh b/plugins/app-starter/skills/fastapi-app/scripts/check-latest.sh new file mode 100755 index 0000000..09a4b6a --- /dev/null +++ b/plugins/app-starter/skills/fastapi-app/scripts/check-latest.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Print current stable versions of the FastAPI stack from PyPI. +# Run before scaffolding. Pin what this reports, not versions from memory. +set -euo pipefail + +pkgs=( + fastapi uvicorn + sqlalchemy asyncpg alembic + pydantic pydantic-settings + python-jose pyjwt bcrypt passlib + google-auth httpx python-multipart + sqladmin ruff pytest pytest-asyncio uv +) + +if ! command -v curl >/dev/null 2>&1; then + echo "curl not found." >&2 + exit 1 +fi + +latest() { + curl -s "https://pypi.org/pypi/$1/json" \ + | python3 -c "import sys,json;print(json.load(sys.stdin)['info']['version'])" 2>/dev/null \ + || echo "?" +} + +printf '%-24s %s\n' "PACKAGE" "LATEST" +printf '%-24s %s\n' "-------" "------" +for p in "${pkgs[@]}"; do + printf '%-24s %s\n' "$p" "$(latest "$p")" +done + +echo +echo "Reminder: SQLAlchemy 2.0 async and Pydantic v2 broke v1 patterns." +echo "Confirm current syntax via Context7 before writing code." diff --git a/plugins/app-starter/skills/flutter-app/SKILL.md b/plugins/app-starter/skills/flutter-app/SKILL.md new file mode 100644 index 0000000..19dac38 --- /dev/null +++ b/plugins/app-starter/skills/flutter-app/SKILL.md @@ -0,0 +1,92 @@ +--- +name: flutter-app +description: Bootstrap a new Flutter mobile app with clean architecture, Riverpod, FVM-pinned SDK, current packages, and no deprecated APIs. Use when the user wants to start, scaffold, or set up a new Flutter app, a cross-platform mobile app, an Android or iOS app in Dart, or asks to "create a new flutter app". Handles BYOK LLM apps, backend-backed apps, Play Store release setup, and clean-architecture feature structure. +--- + +# flutter-app + +Bootstrap a new Flutter app the way this owner builds them: FVM-pinned SDK, clean +architecture (feature-first), Riverpod for state, an Either/Failure error model, +current stable packages, and the house git and CI workflow with release-please +and Play Store delivery. + +First read the shared rules (they override anything you remember): +`../shared/house-rules.md`, `../shared/no-ai-attribution.md`, +`../shared/git-and-ci.md`, `../shared/docs-and-context.md`, +`../shared/hardening.md`, and (for public repos) `../shared/open-source-docs.md`. + +## Step 0. Get the brief, then ask the variant questions (hard stop) + +This is a hard stop. Do not run any scaffolding command until the user has +answered. + +First, get the project brief: one paragraph on what the app does, its main +features, target users, and any hard constraints. If the user has not given one, +ask for it. The brief drives naming, the feature list, and the data model. + +Then ask the variant questions. If a choice has multiple options, ask; do not +assume. Ask in one batch, then proceed. + +1. Repo visibility: private, open-source, or private-plus-open-source. +2. Backend: BYOK (each user supplies their own LLM key, no backend), a custom + backend (Dio + JWT auth), or none yet. See `references/architecture.md`. +3. State codegen: Riverpod with codegen (`@riverpod` + build_runner) or plain + Riverpod with hand-written providers. Default: codegen. +4. Local data: Drift, Isar, shared_preferences only, or none yet. +5. Auth: Google Sign-In, none, or backend-driven. +6. Release target: Play Store (default), App Store, or both. + +If the user already answered some, do not re-ask. + +## Step 1. Pin the SDK with FVM and verify versions + +- Use FVM so the SDK is pinned per project: `fvm use stable` (or a specific + stable). Every command runs through `fvm flutter ...`. +- Run `fvm flutter --version` and record the real Flutter and Dart versions in + the project docs. +- Run `scripts/check-latest.sh` for current stable package versions from pub.dev. + Pin those, not versions from memory (`../shared/house-rules.md` rule 2). +- Pull current docs for Flutter, Riverpod, and any codegen packages via Context7 + before writing code (`../shared/docs-and-context.md`). Riverpod's provider + syntax and codegen naming change between majors; confirm before writing. + +## Step 2. Scaffold with the official CLI + +``` +fvm flutter create --org com.. --platforms=android,ios +``` + +Then add dependencies from `references/stack.md` and lay out the folders from +`references/architecture.md`. + +## Step 3. Apply architecture and conventions + +- Clean-architecture layers, feature structure, Either/Failure model, DI, and the + non-negotiable conventions (use cases, datasource interface plus impl, custom + widgets, extensions, central utils, constants for everything, zero hardcoding): + `references/architecture.md`. +- Riverpod and Flutter do's and don'ts, and code smells to avoid: + `references/best-practices.md`. +- Dependency set and pinning notes (some packages must be pinned to avoid + analyzer conflicts): `references/stack.md`. +- Production hardening (obfuscated release builds, no baked-in secrets, no debug + symbols in git): `../shared/hardening.md`. + +## Step 4. Git, CI, release, docs, security + +- Git branch model, conventional commits, auto-merge, release-please: + `../shared/git-and-ci.md`. +- CI (analyze + test), signing, and Play Store delivery: + `references/quality-gates.md`. +- Gitignore signing keys, keystore, `google-services.json`, and `.env*`. Store + them as CI secrets. Provide `.env.example`. +- Add `docs/` (git-workflow, architecture, release-process) and a README. For a + public repo, ship the full open-source docs set per + `../shared/open-source-docs.md` and run the open-source hard gate in + `../shared/no-ai-attribution.md` before the first push. + +## Step 5. Verify before declaring done + +Run the gates in `references/quality-gates.md`: `fvm flutter analyze` must be +zero issues, `fvm flutter test` green, and the app must build and run. Report +real results. diff --git a/plugins/app-starter/skills/flutter-app/references/architecture.md b/plugins/app-starter/skills/flutter-app/references/architecture.md new file mode 100644 index 0000000..e9c546d --- /dev/null +++ b/plugins/app-starter/skills/flutter-app/references/architecture.md @@ -0,0 +1,108 @@ +# Flutter clean architecture + +Feature-first clean architecture, matching the owner's shipped apps. Strict +layering: `data -> domain <- presentation`. + +``` +lib/ + app/ App widget, root screen (bottom nav), splash + core/ + config/ env wrapper (dart-define-from-file), typed config + constants/ routes, colors, typography, dimensions + di/ get_it + injectable setup, root providers + errors/ Failure sealed class + userMessage / debugMessage + llm/ BYOK: provider presets, config, shared REST decode (if applicable) + network/ ApiClient (Dio) + AuthInterceptor (backend apps) + router/ go_router or onGenerateRoute + storage/ secure storage + shared_preferences wrapper + theme/ AppTheme + usecases/ UseCase base classes + utils/ extensions, logger, helpers + widgets/ shared UI, toasts routed through a global messenger key + features/ + / + data/ datasources (abstract + impl), mappers, repositories (impl) + domain/ entities, repository interfaces, use cases (each a Provider) + presentation/ providers (Notifier / AsyncNotifier), screens, widgets +``` + +## Non-negotiable conventions + +These are hard rules for every Flutter app, not suggestions. + +- Feature-first, clean architecture. Every feature owns its `data`, `domain`, + and `presentation` folders. No cross-feature reach-in; talk through domain + interfaces. +- Use cases in `domain/usecases/`. Presentation calls a use case, never a + repository or datasource directly. Each use case is single-responsibility and + exposed as a Provider. +- Datasources are an abstract interface plus an implementation + (`FooRemoteDataSource` + `FooRemoteDataSourceImpl`). Repositories are an + abstract interface in `domain/` plus an impl in `data/`. Bind impl to interface + through DI (`@LazySingleton(as: AbstractClass)`). Depend on interfaces, never on + a concrete impl. +- Custom widgets live in `core/widgets/` (shared across features) or the + feature's `presentation/widgets/` (feature-local). Build reusable widgets, do + not copy-paste UI. +- Extensions live in `core/utils/` (for example `date_ext.dart`, + `context_ext.dart`, `string_ext.dart`). Reach for an extension before a + free-floating helper function. +- Central utils in `core/utils/`. Shared logic goes here once, not duplicated per + feature. + +## Constants for everything, zero hardcoding + +No magic strings and no magic numbers anywhere in the codebase. Everything lives +in a named constant: + +- Route names in `core/constants/route_names.dart`. +- Colors, typography, spacing, and dimensions in `core/constants/` (or the + theme). Widgets read from these, never inline hex or raw pixel values. +- Storage keys, API paths, durations, and limits in named constants. +- User-facing strings in a constants or localization file, not inline literals. + +If you are about to type a literal string or number into a widget or a service, +stop and put it in a constant first. Reviewers should be able to grep the +constants files and find every tunable value in the app. + +## Error model (Either / Failure) + +Every use case returns `Future>`. Never throw across layers. + +```dart +sealed class Failure { + const factory Failure.database(String msg) = DatabaseFailure; + const factory Failure.network(String msg) = NetworkFailure; + const factory Failure.parse(String msg) = ParseFailure; + const factory Failure.permission(String msg) = PermissionFailure; + const factory Failure.auth(String msg) = AuthFailure; + const factory Failure.rateLimited(String msg) = RateLimitedFailure; + const factory Failure.validation(String msg) = ValidationFailure; // shown verbatim + const factory Failure.unknown(String msg) = UnknownFailure; // raw hidden from UI +} +// failure.userMessage -> safe display copy. failure.debugMessage -> raw, logs only. +``` + +## Riverpod patterns + +- Provider chain: use-case provider reads the repository provider, which reads the + datasource provider; a presentation `AsyncNotifierProvider` calls the use case. +- Use `ref.read` (not `ref.watch`) inside notifier methods. Use `ref.listen` for + side effects like navigation. Never `addPostFrameCallback` in `build`. +- With codegen, run build_runner after any `@riverpod`, `@injectable`, or Drift + table change: + `fvm dart run build_runner build --delete-conflicting-outputs`. + +## Two app shapes + +- BYOK LLM app: no backend. Each user supplies their own key, stored in + `flutter_secure_storage` per provider. LLM providers reached over plain REST + (`http`); add a provider by adding one enum entry. No server secrets. +- Backend-backed app: `ApiClient` (Dio) with module-scoped path prefixes and an + `AuthInterceptor` that attaches the Bearer token and refreshes on 401. No API + keys in the client; all sensitive calls go through the authenticated backend. + +## Environment + +Use `--dart-define-from-file=.env` (KEY=VALUE). Env files are NOT pubspec assets +(security). Gitignore them. Provide `.env.example`. diff --git a/plugins/app-starter/skills/flutter-app/references/best-practices.md b/plugins/app-starter/skills/flutter-app/references/best-practices.md new file mode 100644 index 0000000..cb4d7ad --- /dev/null +++ b/plugins/app-starter/skills/flutter-app/references/best-practices.md @@ -0,0 +1,87 @@ +# Flutter and Riverpod best practices + +Do's and don'ts for writing the app. Read this before writing widgets or +providers. Confirm current Riverpod API details via Context7 first, because the +provider syntax and codegen naming change between majors and this file describes +patterns by intent, not by a pinned version. + +## Riverpod: do + +- Use the latest stable Riverpod and, by default, code generation + (`@riverpod` + build_runner). Let the generator name providers. Regenerate + after every annotation change. +- Keep providers small and single-purpose. One provider does one thing. +- Read dependencies with `ref.watch` inside `build`. It rebuilds when the + dependency changes. +- Inside notifier methods and callbacks, use `ref.read` for a one-off read. Do + not `watch` inside a method body. +- Use `ref.listen` for side effects: navigation, snackbars, dialogs. Never + trigger side effects from `build`. +- Prefer `AsyncNotifier` / `AsyncValue` for anything that loads or fails. Render + loading and error states from `AsyncValue`, do not invent your own bool flags. +- Use `autoDispose` (the codegen default) for screen-scoped state so it resets + when the user leaves. Keep only truly global state alive. +- Use `family` to parameterize a provider (for example by id) instead of stuffing + a map inside one provider. +- Inject the repository or datasource through a provider so tests can override it + with `ProviderScope(overrides: [...])`. + +## Riverpod: do not + +- Do not create providers inside `build` or inside other providers ad hoc. + Declare them at top level. +- Do not `ref.watch` inside a button callback or a notifier method. That is a + common source of rebuild bugs. Use `ref.read` there. +- Do not hold `BuildContext` across an await inside a notifier. Notifiers must not + depend on context. +- Do not mutate state in place. Emit a new immutable state object so listeners + fire. +- Do not put business logic in the widget. Widgets read state and call methods; + logic lives in the notifier, use case, or service. +- Do not swallow errors. Surface them through `AsyncValue.error` or the + Either/Failure model, then show `failure.userMessage`. +- Do not use `StateProvider` for anything non-trivial. Reach for a notifier. + +## Flutter widgets: do + +- Compose small widgets. Extract a subtree into its own widget instead of a + private `_buildX()` method, so it gets its own rebuild scope and a `const` + constructor. +- Mark widgets and their constructors `const` wherever possible. It skips + needless rebuilds. +- Split large screens into feature-local widgets under `presentation/widgets/`. +- Handle every `AsyncValue` state in the UI: data, loading, and error. +- Dispose controllers, focus nodes, timers, and stream subscriptions in + `dispose`. Use `autoDispose` providers to avoid leaks in state. +- Keep layout constants (spacing, radius, sizes) in central constants, never + inline numbers (see `architecture.md`, constants for everything). + +## Flutter widgets: do not + +- Do not do expensive work in `build`. No network calls, no heavy computation, no + sorting a large list every frame. Move it into a provider. +- Do not rebuild the whole screen for one changing value. Scope the watch to the + smallest widget, or select a slice with `ref.watch(provider.select(...))`. +- Do not nest deeply when a widget extraction reads clearer. Deep nesting is a + smell. +- Do not use `!` to force-unwrap nullables casually. Handle null. +- Do not block the UI isolate with heavy work. Use `compute` or an isolate. +- Do not hardcode strings, colors, or numbers into widgets. Pull from constants + and the theme. + +## Code smells to avoid (all layers) + +- God files and god classes. Split by responsibility. +- Copy-pasted UI or logic. Extract a widget, an extension, or a util. +- Magic strings and magic numbers. Name them. +- Business logic leaking into the presentation layer, or data access leaking past + the repository interface. +- Throwing across layers. Return `Either`. +- Catch blocks that hide the error or print and continue. +- Unused code, dead providers, and commented-out blocks. Delete them. + +## The gate + +`fvm flutter analyze lib/` must report zero issues before any commit. Treat every +analyzer lint as a real problem, not noise. Enable a strict lint set +(`flutter_lints` or stricter) in `analysis_options.yaml`. diff --git a/plugins/app-starter/skills/flutter-app/references/quality-gates.md b/plugins/app-starter/skills/flutter-app/references/quality-gates.md new file mode 100644 index 0000000..76e2b55 --- /dev/null +++ b/plugins/app-starter/skills/flutter-app/references/quality-gates.md @@ -0,0 +1,63 @@ +# Flutter quality gates, CI, and release + +## Local gates (run before every commit and in CI) + +``` +fvm flutter pub get +fvm dart run build_runner build --delete-conflicting-outputs # if using codegen +fvm flutter analyze lib/ # must be zero issues +fvm flutter test +``` + +Zero analyzer issues is a hard gate. A lefthook or git pre-commit hook can run +analyze and test locally before a commit lands. + +## CI workflow + +`.github/workflows/ci.yml`, a job on PRs into `develop` and `main`: + +```yaml +name: CI +on: + pull_request: + branches: [develop, main] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + cache: true + - run: flutter pub get + - run: dart run build_runner build --delete-conflicting-outputs + - run: flutter analyze + - run: flutter test +``` + +Match the Flutter version to the FVM pin. Pin action majors to current when you +write this. + +## Signing and secrets (Android) + +- `android/key.properties` and `android/app/upload-keystore.jks`: gitignored. + Store the keystore base64 and passwords as GitHub Actions secrets. +- `android/app/google-services.json`: gitignored, stored as a secret, written at + build time. +- Back up the keystore. Losing it means you can never update the app. +- The Android application id is permanent after first Play Store publish. Choose + `com..` deliberately. + +## Release with release-please + +- `release-please` opens a version + CHANGELOG PR from conventional commits on + pushes to `main`. Merging it tags the release. +- A `release.yml` triggered on the `v*.*.*` tag builds a signed AAB and uploads + it to the Play Store track. Never bump the pubspec version or tag by hand when + release-please is in use. + +## Verify before declaring done + +`fvm flutter analyze lib/` clean, `fvm flutter test` green, and the app builds +and launches. Report real results, including analyzer output if not clean. diff --git a/plugins/app-starter/skills/flutter-app/references/stack.md b/plugins/app-starter/skills/flutter-app/references/stack.md new file mode 100644 index 0000000..d4e7e73 --- /dev/null +++ b/plugins/app-starter/skills/flutter-app/references/stack.md @@ -0,0 +1,57 @@ +# Flutter stack + +Default dependency set from the owner's shipped apps. Pin to the live stable +versions from `scripts/check-latest.sh`, not the numbers here. Some packages need +deliberate pinning; see the pinning notes. + +## SDK + +- Managed by FVM, pinned per project. Run everything as `fvm flutter ...` and + `fvm dart ...`. Record the exact Flutter and Dart versions in project docs. + +## State and architecture + +- `flutter_riverpod` + `riverpod_annotation` (codegen path) with + `riverpod_generator` + `build_runner` in dev deps. +- `fpdart` for the `Either` return type across use cases. +- DI: `get_it` + `injectable` (+ `injectable_generator`). +- Routing: `go_router` for declarative or deep-linked apps; imperative + `Navigator` with `onGenerateRoute` for simpler ones. + +## Data + +- Local DB: `drift` (+ `drift_dev`) for relational, or `isar` for object storage. +- Network: `dio` with an `ApiClient` wrapper and an auth interceptor + (Bearer + refresh on 401), or plain `http` for a keyless BYOK REST client. +- Secure storage: `flutter_secure_storage` for tokens and API keys. Non-sensitive + prefs: `shared_preferences`. + +## UI and utilities + +- `flutter_screenutil` for responsive sizing (design size, `.w` / `.h` / `.sp`). +- Charts: `fl_chart`. Fonts: bundle Inter and a monospace, or use `google_fonts`. +- Platform info for bug reports: `device_info_plus`, `package_info_plus`, + `connectivity_plus`. +- Firebase when needed: `firebase_core`, `firebase_crashlytics`. + +## Pinning notes (real conflicts seen in shipped apps) + +Some codegen packages conflict across minor bumps. When you hit an analyzer or +build_runner conflict, pin the offending package rather than chasing the newest. +Historically seen: + +- `drift` newer minors have conflicted with `riverpod_generator`'s analyzer + constraint. If build_runner fails, pin `drift` to the last compatible minor. +- `injectable` and `injectable_generator` must be on matching versions; a + generator bump has shipped breaking DI changes. + +Do not blindly copy old pins from memory. Try latest stable first; pin only when +the build actually breaks, and note why in a comment next to the pin. + +## What NOT to do + +- Do not throw from domain or data layers. Return `Either`. +- Do not use a deprecated Riverpod provider style. The `@riverpod` codegen naming + (class `FooNotifier` generates `fooProvider`, not `fooNotifierProvider`) and + the provider APIs change between majors. Confirm with current Riverpod docs. +- Do not skip `fvm flutter analyze`. Zero issues before any commit. diff --git a/plugins/app-starter/skills/flutter-app/scripts/check-latest.sh b/plugins/app-starter/skills/flutter-app/scripts/check-latest.sh new file mode 100755 index 0000000..fe9d4ea --- /dev/null +++ b/plugins/app-starter/skills/flutter-app/scripts/check-latest.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Print current stable versions of the Flutter stack from pub.dev. +# Run before scaffolding. Pin what this reports, not versions from memory. +set -euo pipefail + +pkgs=( + flutter_riverpod riverpod_annotation riverpod_generator + fpdart get_it injectable injectable_generator + go_router dio http + drift drift_dev isar + flutter_secure_storage shared_preferences + flutter_screenutil fl_chart google_fonts + device_info_plus package_info_plus connectivity_plus + firebase_core firebase_crashlytics + build_runner +) + +if ! command -v curl >/dev/null 2>&1; then + echo "curl not found." >&2 + exit 1 +fi + +latest() { + # pub.dev API returns the latest stable in .latest.version + curl -s "https://pub.dev/api/packages/$1" \ + | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('latest',{}).get('version','?'))" 2>/dev/null \ + || echo "?" +} + +printf '%-28s %s\n' "PACKAGE" "LATEST" +printf '%-28s %s\n' "-------" "------" +for p in "${pkgs[@]}"; do + printf '%-28s %s\n' "$p" "$(latest "$p")" +done + +echo +echo "Flutter SDK: run 'fvm releases' or 'fvm flutter --version' for the pinned" +echo "stable. Confirm Riverpod codegen naming and provider APIs via Context7." +echo "If build_runner conflicts, pin the offending package and note why." diff --git a/plugins/app-starter/skills/nextjs-app/SKILL.md b/plugins/app-starter/skills/nextjs-app/SKILL.md new file mode 100644 index 0000000..9fdd3eb --- /dev/null +++ b/plugins/app-starter/skills/nextjs-app/SKILL.md @@ -0,0 +1,88 @@ +--- +name: nextjs-app +description: Bootstrap a new Next.js (App Router, TypeScript) web app with current packages and no deprecated APIs. Use when the user wants to start, scaffold, or set up a new Next.js project, a React web app, a SaaS or dashboard or landing page on Next.js, or asks to "create a new nextjs app". Handles private, open-source, and private-plus-open-source variants, Prisma and Postgres, next-auth, Tailwind, and shadcn or Mantine. +--- + +# nextjs-app + +Bootstrap a new Next.js web app the way this owner builds them: App Router, +TypeScript strict, current stable packages, no deprecated APIs, a clean feature +structure, and the house git and CI workflow. + +First read these shared rules (they override anything you remember): +`../shared/house-rules.md`, `../shared/no-ai-attribution.md`, +`../shared/git-and-ci.md`, `../shared/docs-and-context.md`, +`../shared/hardening.md`, and (for public repos) `../shared/open-source-docs.md`. + +## Step 0. Get the brief, then ask the variant questions (hard stop) + +This is a hard stop. Do not run any scaffolding command until the user has +answered. + +First, get the project brief: one paragraph on what the app does, its main +features, target users, and any hard constraints. If the user has not given one, +ask for it. The brief drives naming, the route groups, and the data model. + +Then present the variant choices below, wait for the answers, and build. If a +choice has multiple options, ask; do not assume. Ask in one batch. + +1. Repo visibility: private, open-source (public), or private-plus-open-source + (a private product with a separate public core or SDK). See + `references/variants.md`. +2. Data layer: Prisma + Postgres (default), a different DB, or none yet. +3. Auth: next-auth v5 (default), Clerk, or none yet. +4. UI kit: shadcn/ui + Tailwind (default), Mantine, or plain Tailwind. +5. Deploy target: Vercel (default) or self-host (Docker). +6. Package manager: pnpm (default) or npm. + +If the user already answered some of these in their prompt, do not re-ask. + +## Step 1. Verify environment and current versions + +- Check Node (`node -v`, want the current LTS or newer) and the package manager. +- Run `scripts/check-latest.sh` to get live stable versions from npm. Pin those, + not versions from memory. See `../shared/house-rules.md` rule 2. +- Pull current Next.js docs before writing framework code + (`../shared/docs-and-context.md`). Recent Next.js ships docs in + `node_modules/next/dist/docs/`; read the relevant guide and obey deprecation + notices. + +## Step 2. Scaffold with the official CLI + +Use the official generator so you inherit its current defaults: + +``` +pnpm create next-app@latest --typescript --app --eslint --tailwind --src-dir --import-alias "@/*" +``` + +Adjust flags to the answers. Let the CLI pick the current Next major; do not +force a version you remember. After it runs, read `references/stack.md` for the +exact dependency set to add and `references/structure.md` for the folder layout. + +## Step 3. Apply house structure and conventions + +- Folder layout, data layer, auth, and server-action patterns: + `references/structure.md`. +- Dependency set and why each is chosen: `references/stack.md`. +- Variant-specific setup (LICENSE, README tone, monorepo split, secret + handling): `references/variants.md`. +- Production hardening so the shipped app does not leak secrets or internals: + `../shared/hardening.md`. + +## Step 4. Git, CI, docs, security + +- Initialize git, set the branch model, and wire CI and auto-merge per + `../shared/git-and-ci.md`. +- Write the CI workflow and quality gates from `references/quality-gates.md`. +- Add `docs/` and README per `../shared/docs-and-context.md`. +- For a public repo, ship the full open-source docs set (LICENSE, CONTRIBUTING, + CODE_OF_CONDUCT, SECURITY, issue and PR templates, CHANGELOG via release-please) + per `../shared/open-source-docs.md`, and run the open-source hard gate in + `../shared/no-ai-attribution.md` before the first push. +- Gitignore `.env*`, add `.env.example`. Never commit secrets. + +## Step 5. Verify before declaring done + +Run the quality gates in `references/quality-gates.md` (typecheck, lint, +production build, and a dev-server smoke check). Report real results. If a build +fails, fix it or say so with the output. Do not claim done on an unbuilt app. diff --git a/plugins/app-starter/skills/nextjs-app/references/quality-gates.md b/plugins/app-starter/skills/nextjs-app/references/quality-gates.md new file mode 100644 index 0000000..f9e1f37 --- /dev/null +++ b/plugins/app-starter/skills/nextjs-app/references/quality-gates.md @@ -0,0 +1,57 @@ +# Next.js quality gates and CI + +## Local gates (run before every commit and in CI) + +``` +pnpm install --frozen-lockfile +pnpm lint # eslint src/ +pnpm typecheck # tsc --noEmit +pnpm build # prisma generate && next build +``` + +Add a `typecheck` script (`tsc --noEmit`) if `create-next-app` did not. The +production `build` is the real gate; a passing dev server is not enough. + +## CI workflow + +`.github/workflows/ci.yml`, one `build` job on PRs into `develop` and `main`: + +```yaml +name: CI +on: + pull_request: + branches: [develop, main] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm lint + - run: pnpm typecheck + - run: pnpm build + env: + # a dummy DATABASE_URL so prisma generate and next build succeed + DATABASE_URL: postgresql://user:pass@localhost:5432/db +``` + +Pin action versions to the current majors when you write this; do not trust the +numbers above blindly. Set branch protection to require the `build` job, then use +`gh pr merge --squash --auto` per `../shared/git-and-ci.md`. + +## Deploy + +- Vercel: connect the repo, set env vars in the Vercel dashboard, `main` is the + production branch. Preview deploys on PRs come for free. +- Self-host: a `Dockerfile` using the Next standalone output and a + `docker-compose.yml` with the app plus Postgres. + +## Smoke check before declaring done + +Start the dev server, load the root route, confirm no runtime or hydration +errors in the console. Report the real result. diff --git a/plugins/app-starter/skills/nextjs-app/references/stack.md b/plugins/app-starter/skills/nextjs-app/references/stack.md new file mode 100644 index 0000000..e16fa27 --- /dev/null +++ b/plugins/app-starter/skills/nextjs-app/references/stack.md @@ -0,0 +1,56 @@ +# Next.js stack + +This is the default dependency set, drawn from the owner's shipped apps. It is a +starting point, not a lockfile. Always pin to the live stable versions from +`scripts/check-latest.sh`, not the numbers written here. + +## Core + +- `next` (App Router), `react`, `react-dom` at the current stable majors. +- TypeScript strict mode on. `@types/node`, `@types/react`, `@types/react-dom`. +- ESLint flat config (`eslint.config.mjs`) with `eslint-config-next`. +- Package manager: pnpm. Set `engines` for node and pnpm in package.json. + +## Data layer (default: Prisma + Postgres) + +- `prisma` and `@prisma/client`. +- The current Prisma major uses a driver adapter for Postgres: + `@prisma/adapter-pg` + `pg`. Wire the adapter in the Prisma client init; do not + copy an old direct-connection setup from memory. Confirm the current pattern in + the Prisma docs before writing the client. +- `postinstall` runs `prisma generate`. Build script runs + `prisma generate && next build`. +- Scripts: `db:push`, `db:migrate`, `db:seed` (via `tsx`), `db:studio`, using + `dotenv-cli` to load `.env`. + +## Auth (default: next-auth v5) + +- `next-auth` (v5 line) + `@auth/prisma-adapter`. v5 is the current standard even + though it carries a beta tag; note that in one line where you pin it. + +## UI (default: shadcn/ui + Tailwind v4) + +- Tailwind v4 with `@tailwindcss/postcss`. No legacy `tailwind.config.js` content + array unless the installed version needs it; confirm the current setup. +- shadcn/ui components (Radix primitives, `class-variance-authority`, `clsx`, + `tailwind-merge`, `lucide-react`). Initialize with the shadcn CLI so + `components.json` and the current component source land correctly. +- Alternative UI kit: Mantine (`@mantine/core` + hooks + form + dates + + notifications, `postcss-preset-mantine`). Pick one kit, not both. + +## Common libraries + +- Forms and validation: `react-hook-form` + `@hookform/resolvers` + `zod`. +- Client state: `zustand`. Server state: `@tanstack/react-query` when you fetch + from a separate API; for server components and server actions you often need + neither. +- Tables: `@tanstack/react-table`. Charts: `recharts`. Dates: `date-fns` or + `dayjs`. Toasts: `sonner`. Theme: `next-themes`. +- Analytics on Vercel: `@vercel/analytics`. + +## What NOT to do + +- Do not use the Pages Router. App Router only. +- Do not use `getServerSideProps` / `getStaticProps` (Pages-era APIs). +- Do not reach for a version or API from memory. The Next, React, Prisma, and + Tailwind majors move fast; verify against `check-latest.sh` and current docs. diff --git a/plugins/app-starter/skills/nextjs-app/references/structure.md b/plugins/app-starter/skills/nextjs-app/references/structure.md new file mode 100644 index 0000000..bb2f129 --- /dev/null +++ b/plugins/app-starter/skills/nextjs-app/references/structure.md @@ -0,0 +1,49 @@ +# Next.js folder structure and patterns + +Feature-first layout under `src/`, matching the owner's shipped apps. + +``` +src/ + app/ + (auth)/ route group for sign-in and sign-up + (app)/ route group for the authenticated product + api/ route handlers (webhooks, integrations) + layout.tsx + page.tsx + components/ + ui/ shadcn primitives (generated) + layout/ shell, nav, sidebar + shared/ cross-feature widgets + charts/ + features/ optional: per-feature folders when the app grows + lib/ framework glue: db client, auth config, utils + actions/ server actions, grouped by domain + repositories/ data access, one module per aggregate + schemas/ zod schemas, shared client and server + services/ business logic that is not a server action + stores/ zustand stores + auth/ auth helpers and session access +``` + +## Patterns + +- Server Components by default. Add `"use client"` only where interactivity or + browser APIs require it. +- Data access goes through `repositories/`. Server actions in `actions/` call + repositories; components do not touch the DB client directly. +- Validate every server action input with a `zod` schema from `schemas/`. Never + trust client input. +- The Prisma client is a single instance in `lib/` guarded against hot-reload + duplication in dev. +- Route handlers under `app/api/` are for webhooks and external integrations, not + for your own UI data. Prefer server actions and server components for internal + data flow. +- Keep secrets in env, read through a typed config module in `lib/`. Never inline + `process.env` reads across the codebase. + +## Files to create at the root + +- `.env.example` with every key blank or placeholder. +- `eslint.config.mjs`, `tsconfig.json` (strict), `next.config.ts`. +- `prisma/schema.prisma` and `prisma/seed.ts` when using Prisma. +- `docker-compose.yml` for local Postgres when using Prisma + Postgres. diff --git a/plugins/app-starter/skills/nextjs-app/references/variants.md b/plugins/app-starter/skills/nextjs-app/references/variants.md new file mode 100644 index 0000000..33d9cec --- /dev/null +++ b/plugins/app-starter/skills/nextjs-app/references/variants.md @@ -0,0 +1,43 @@ +# Next.js variants: private, open-source, private + open-source + +Ask the visibility question first (SKILL step 0), then set the repo up for that +variant. The code is the same; what changes is licensing, README tone, secret +posture, and repo split. + +## Private (default product repo) + +- `gh repo create --private`. +- README can be terse and internal: what it is, how to run, env keys, deploy. +- No LICENSE required. If you add one, use a proprietary "all rights reserved" + note, not MIT. +- Secrets in Vercel env and GitHub Actions secrets. `.env*` gitignored. +- Add `CONTRIBUTING.md` only if teammates will work in it. + +## Open-source (public) + +- `gh repo create --public`. +- Add `LICENSE` (MIT unless the owner says otherwise), `README.md` written for + strangers (badges, quickstart, screenshots), `CONTRIBUTING.md`, + `CODE_OF_CONDUCT.md`, and `SECURITY.md`. +- Add `.github/ISSUE_TEMPLATE/` and a PR template. +- Absolutely no secrets, no real credentials, no internal URLs in history. If any + secret ever touched a commit, rotate it and scrub history before going public. +- Ship a working `.env.example` and a seed path so a stranger can run it. + +## Private + open-source (product + public core) + +Two common shapes: + +1. Monorepo with `apps/` split (the owner uses `apps/web`, `apps/mobile`). The + public repo holds the shareable core; the private product consumes it. Keep + proprietary code out of the public app folder. +2. Two repos: a public library or SDK, and a private app that depends on it. + +Pick based on the owner's answer. Default to a monorepo with `apps/web` when they +already work that way. Draw a hard line: anything with secrets, paid-feature +gating, or customer data stays private. The public side gets an MIT LICENSE and a +stranger-facing README; the private side stays terse and internal. + +In all cases the no-AI-attribution rule applies to every published file +(`../shared/no-ai-attribution.md`). A public repo is the worst place to leak an +AI-tool file or AI-cadence prose, so scan before the first push. diff --git a/plugins/app-starter/skills/nextjs-app/scripts/check-latest.sh b/plugins/app-starter/skills/nextjs-app/scripts/check-latest.sh new file mode 100755 index 0000000..3f81893 --- /dev/null +++ b/plugins/app-starter/skills/nextjs-app/scripts/check-latest.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Print current stable versions of the Next.js stack from the npm registry. +# Run before scaffolding. Pin what this reports, not versions from memory. +set -euo pipefail + +pkgs=( + next react react-dom typescript + eslint eslint-config-next + prisma @prisma/client @prisma/adapter-pg pg + next-auth @auth/prisma-adapter + tailwindcss @tailwindcss/postcss + zod react-hook-form @hookform/resolvers + zustand @tanstack/react-query @tanstack/react-table + recharts date-fns sonner next-themes lucide-react + @mantine/core +) + +if ! command -v npm >/dev/null 2>&1; then + echo "npm not found. Install Node first." >&2 + exit 1 +fi + +printf '%-28s %s\n' "PACKAGE" "LATEST" +printf '%-28s %s\n' "-------" "------" +for p in "${pkgs[@]}"; do + v=$(npm view "$p" version 2>/dev/null || echo "?") + printf '%-28s %s\n' "$p" "$v" +done + +echo +echo "Reminder: prefer latest stable. next-auth v5 ships a beta tag but is the" +echo "current standard. Confirm framework APIs via Context7 before writing code." diff --git a/plugins/app-starter/skills/shared/docs-and-context.md b/plugins/app-starter/skills/shared/docs-and-context.md new file mode 100644 index 0000000..a91b86c --- /dev/null +++ b/plugins/app-starter/skills/shared/docs-and-context.md @@ -0,0 +1,43 @@ +# Docs and live context (all stacks) + +## Always pull current docs before writing framework code + +Your training data lags the installed packages. Before writing framework-specific +code, fetch current docs. Two good sources: + +1. Context7 (preferred for library and framework docs). If the `ctx7` CLI or a + Context7 MCP server is available: + ``` + npx ctx7@latest library "" "" + npx ctx7@latest docs "/org/project" "" + ``` + Use the official library name with correct punctuation ("Next.js", not + "nextjs"). Resolve the library id first, then fetch docs. + +2. The framework's own vendored docs when it ships them. Recent Next.js ships + docs under `node_modules/next/dist/docs/`. Read the relevant guide there and + heed deprecation notices. Treat any local file named to warn you (for example + an `AGENTS.md` that says "this is NOT the framework you know") as ground truth + over your memory. + +Do this even for frameworks you think you know well. The point is not to learn +the framework, it is to catch the parts that changed since your cutoff. + +## Docs to write into every output project + +Create a `docs/` folder with: + +- `git-workflow.md` branch strategy, daily flow, hotfix, CI table. +- `architecture.md` layers, folder structure, the core patterns. +- `release-process.md` how a release goes out, environments, secrets. + +Keep a short `README.md` at the repo root: what the app is, how to run it, how to +contribute. Match the visibility variant (a public repo README is written for +strangers; a private one can be terse). + +## Optional: graphify knowledge graph + +If the owner uses graphify, add a short note to the project README or internal +docs pointing at `graphify-out/` and how to query it. Do not add a committed +`CLAUDE.md` for this; keep AI-tool files out of the repo (see +`no-ai-attribution.md`). diff --git a/plugins/app-starter/skills/shared/git-and-ci.md b/plugins/app-starter/skills/shared/git-and-ci.md new file mode 100644 index 0000000..102d1c2 --- /dev/null +++ b/plugins/app-starter/skills/shared/git-and-ci.md @@ -0,0 +1,50 @@ +# Git and CI (all stacks) + +The same branch model and merge workflow across every app. + +## Branch model + +``` +main production. Deploys go from here. Protected. +develop integration. Feature branches land here first. CI runs on PRs. +feature/* daily work. Branch from develop, PR back to develop. +hotfix/* critical prod fix. Branch from main, PR to main, back-merge to develop. +release/* version bump when not using release-please. Branch from develop, PR to main. +``` + +For a small solo project you may start with just `main` + `develop`. Add +`staging` only when a real pre-prod environment exists. + +## Conventional commits + +`feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`, `perf:`, `ci:`. +Subject in the imperative, under about 70 chars. Body only when the "why" is not +obvious from the subject. Authored as the human owner. No AI trailers (see +`no-ai-attribution.md`). + +## Auto-merge on green CI + +Do not poll-and-merge by hand. For each PR, enable GitHub auto-merge so it merges +itself the moment required checks pass: + +``` +gh pr merge --squash --auto +``` + +Enable "Allow auto-merge" and "Automatically delete head branches" in repo +settings once, up front. Never bypass CI with `--admin` except for a +release-automation bot PR that CI cannot run on by design. + +## CI baseline + +A `build` job on every PR into `develop` and `main` that runs the stack's +quality gates (lint, typecheck, tests, and a production build). Branch protection +requires that job to pass before merge. See each skill's `quality-gates.md` for +the exact commands. + +## Release automation + +Prefer release-please to manage version bumps and CHANGELOG from conventional +commits. It opens a release PR on pushes to `main`; merging it tags the release, +which triggers the deploy or publish workflow. Never hand-edit the version or +create tags manually when release-please is in use. diff --git a/plugins/app-starter/skills/shared/hardening.md b/plugins/app-starter/skills/shared/hardening.md new file mode 100644 index 0000000..5cb96e7 --- /dev/null +++ b/plugins/app-starter/skills/shared/hardening.md @@ -0,0 +1,63 @@ +# Hardening: make the shipped app hard to reverse engineer + +Every app these skills scaffold should be built so that a shipped artifact leaks +as little as possible: no secrets, no readable internals, no debug surface. Apply +the parts that fit the stack. + +## Rules for all stacks + +- No secrets in the client or in any shipped artifact. Keys, tokens, and DB + credentials live only in the platform secret store or, for BYOK apps, in the + user's own secure storage. A secret compiled into a binary or a browser bundle + is a secret you have published. +- Ship production builds only. Debug builds carry symbols, assertions, and + verbose logging that hand an attacker a map. +- Do not commit debug symbols, source maps, or mapping files. Gitignore them and + keep them out of the published artifact. Archive them privately for crash + symbolication. +- Errors shown to a client are generic. Full stack traces, framework versions, + and internal paths stay in server logs, never in a response or a UI. +- Turn off any debug or introspection surface in production (debug flags, admin + panels behind auth, verbose headers). + +## Flutter + +- Release builds with obfuscation and split debug info: + ``` + fvm flutter build appbundle --release \ + --obfuscate --split-debug-info=build/symbols + ``` + Keep `build/symbols` out of git; archive it to symbolicate crashes. +- Android: keep R8 or ProGuard shrinking and obfuscation on for release. Do not + disable minification. +- Never bundle API keys or secrets as assets or dart-defines that ship in the + binary. BYOK keys stay in `flutter_secure_storage`; backend calls go through an + authenticated server, not a key baked into the app. +- Strip logging in release. Do not print tokens, payloads, or internal state. + +## Next.js + +- Production build only for deploys. Keep browser source maps off in production + (`productionBrowserSourceMaps: false` unless you have a private symbolication + need). +- Only expose env vars you intend to. Client code sees `NEXT_PUBLIC_` vars only; + everything else is server-only. Never pass a server secret into a client + component or a public env var. +- Keep data access and secrets in server components, server actions, and route + handlers. The client bundle should carry no credentials and no privileged + logic. +- Do not ship verbose error pages in production. Return generic errors; log + detail server-side. + +## FastAPI + +- Disable or lock down the interactive docs and schema in production. Serve + `/docs`, `/redoc`, and `/openapi.json` only in non-prod, or put them behind + auth. Set `docs_url=None` and `openapi_url=None` when disabled. +- Return generic error bodies. Register exception handlers so no stack trace, + SQL, or internal path reaches the client. Keep detail in structured logs. +- Turn debug off in production settings. Do not run with `--reload` or a debug + server in prod. +- Lock CORS to known origins. Do not use a wildcard in production. +- Rate-limit auth and sensitive endpoints. Do not leak whether a user exists in + login or reset responses. diff --git a/plugins/app-starter/skills/shared/house-rules.md b/plugins/app-starter/skills/shared/house-rules.md new file mode 100644 index 0000000..369a560 --- /dev/null +++ b/plugins/app-starter/skills/shared/house-rules.md @@ -0,0 +1,72 @@ +# House rules (all stacks) + +These rules apply to every app the starter skills scaffold. Read them before +writing any code. They exist because a model's training data is always older +than the packages you are about to install. + +## 1. Trust the injected current date, not your training cutoff + +Claude Code injects the real current date into the session. Believe it. Your +training cutoff is months behind it. Any statement like "the latest version is +X" from memory is a guess and is probably wrong. Confirm versions live (rule 2). + +## 2. Latest stable packages, verified live (never hardcoded) + +Order of operations, every time: + +1. Read the injected current date (rule 1). That is "now". +2. As of that date, query the real registry for current stable versions by + running the skill's `scripts/check-latest.sh` (npm, pub.dev, PyPI). +3. Pin what the script reports. + +No version number is hardcoded anywhere in these skills. The `references/*.md` +files describe the stack by package NAME and never carry a pinned version, +because versions go stale the moment they are written. If you ever see a version +number in a reference file, treat it as a bug and ignore it in favor of the live +check. Pin what the registry says now, not what you remember. + +- Prefer the latest STABLE release. Do not pull prereleases (alpha, beta, rc) + unless the ecosystem norm requires it (for example next-auth v5 is beta but is + the current auth standard). When you use a prerelease, say why in one line. +- After install, run the project's own version print (`next --version`, + `flutter --version`, `pip show fastapi`) and record the real installed + versions in the project's docs. + +## 3. No deprecated APIs + +Deprecated code is the single most common failure when a model scaffolds with +stale memory. Defend against it: + +- Consult current docs through Context7 (see `docs-and-context.md`) for the + framework before writing framework-specific code. Do this even for frameworks + you think you know. APIs move. +- Heed every deprecation warning the tooling prints. Do not silence it, fix it. +- When the installed major version differs from what you remember, assume the + API changed and read the migration notes before writing code. + +## 4. Write like a human developer + +The output repo must read as if a human wrote it. See `no-ai-attribution.md` +for the hard rules. In short: plain ASCII punctuation, no em or en dashes, no +curly quotes, no AI-cadence prose, and no reference to any AI tool anywhere in +the code, comments, docs, commits, or metadata. + +## 5. Git, commits, and CI + +Follow `git-and-ci.md`: conventional commits authored as a human, feature branch +into an integration branch, PR, and auto-merge on green CI. No AI co-author +trailers, ever. + +## 6. Security defaults + +- Never commit secrets. `.env*`, keystores, service-account JSON, and signing + credentials are gitignored from the first commit. +- Provide a `.env.example` with keys and blank or placeholder values. +- Secrets live in the platform secret store (GitHub Actions secrets, Vercel env, + platform keychain), never in the repo. + +## 7. Ask the few decisions that change scaffolding, then proceed + +Each skill asks a short set of variant questions up front (license, visibility, +deploy target, and so on). Ask those, then build without further hand-holding. +Do not re-litigate settled choices or narrate options you will not take. diff --git a/plugins/app-starter/skills/shared/no-ai-attribution.md b/plugins/app-starter/skills/shared/no-ai-attribution.md new file mode 100644 index 0000000..a4b333e --- /dev/null +++ b/plugins/app-starter/skills/shared/no-ai-attribution.md @@ -0,0 +1,64 @@ +# No AI attribution, and nothing that reads as AI-written + +This is a hard rule for every app these skills scaffold. The generated repo must +look like a human developer wrote it. Apply this to the OUTPUT project, not to +this skills repo itself (a Claude Code plugin is openly a Claude Code plugin). + +## Never put AI references in the output repo + +Do not add, commit, or push any reference to Claude, an AI, an assistant, an +agent, Copilot, or any AI tool anywhere in the generated project: + +- not in code or code comments +- not in README, docs, or any markdown +- not in commit messages, commit author name, or commit email +- not in package.json, pubspec.yaml, pyproject, config, or HTML meta/generator +- not as a co-author trailer or a "generated by" line + +Never commit AI-tool files into the output repo: `CLAUDE.md`, `AGENTS.md`, +`.cursor/`, `.github/copilot-instructions.md`, or similar. Add them to +`.gitignore`. If a CLI or framework injects one, delete it and confirm it stays +ignored. + +The only acceptable use of "AI" in an output repo is describing a product +feature (for example "AI-graded practice with your own API key"). That describes +a capability. It must never imply the app itself was built by an AI. + +## Nothing may READ as AI-written + +- No em dashes or en dashes anywhere. Use commas, hyphens, or separate + sentences. Same for curly quotes, curly apostrophes, and the ellipsis + character. Use plain ASCII: `'`, `"`, `...`. +- No AI-cadence prose. Avoid the tells: over-balanced "not only X but also Y", + "it's worth noting", "in the world of", "delve", "seamless", "robust", + "leverage", relentless tricolons. Write plain and direct. +- No AI-sounding or AI-referencing comments. Comments explain the code like a + human dev would. + +## Commits + +Author commits as the human owner in normal conventional-commit style (`feat:`, +`fix:`, `chore:`, `docs:`). No AI co-author trailers. No "generated by" lines. + +Before any commit, scan the diff for em dashes, curly punctuation, AI-cadence +text, and any AI reference. If in doubt, rewrite plainer. + +## Open-source: the hard gate + +For a public repo the bar is absolute. Never push anything that even hints an AI +was involved in building the project. Before the first public push, and before +every push after: + +- Scan the full working tree, not just the diff, for AI-tool files + (`CLAUDE.md`, `AGENTS.md`, `.cursor/`, `.claude/`, `.github/copilot-*`, + `.aider*`, `.continue/`) and remove them. Confirm they are gitignored. +- Grep the entire history, not just the tip, for em dashes, curly quotes, the + ellipsis character, AI-cadence phrases, and the words claude, copilot, chatgpt, + "generated by", or "co-authored-by". If any secret or AI reference ever landed + in a past commit, scrub history (or start a clean history) before publishing. +- Check commit author and email on every commit. All human. No bot or AI author. +- Check package metadata, HTML meta and generator tags, and CI config for + generator or tool references. + +When unsure whether something reads as AI-written, it does. Rewrite it. A public +repo is permanent once cloned or indexed, so treat the first push as final. diff --git a/plugins/app-starter/skills/shared/open-source-docs.md b/plugins/app-starter/skills/shared/open-source-docs.md new file mode 100644 index 0000000..b46b2de --- /dev/null +++ b/plugins/app-starter/skills/shared/open-source-docs.md @@ -0,0 +1,43 @@ +# Open-source docs checklist + +When the visibility variant is open-source (public) or the public side of a +private-plus-open-source split, the repo must ship the documents a stranger and a +contributor expect. Create all of these before the first public push. + +## Required + +- `README.md` written for strangers: what it is, a screenshot or demo, quickstart + (clone, install, env, run), and how to contribute. Not the terse internal + version. +- `LICENSE` a real license file (MIT unless the owner says otherwise). Set the + copyright holder and year. +- `CONTRIBUTING.md` how to set up, branch, commit (Conventional Commits), run the + checks, and open a PR. +- `CODE_OF_CONDUCT.md` the behavior standard and how to report. +- `SECURITY.md` how to report a vulnerability privately (advisory or email), and + what is in scope. +- `.gitignore` covering env files, secrets, build output, and AI-tool files. +- `.env.example` every key present, values blank or placeholder, so a stranger + can run it. + +## GitHub templates + +- `.github/ISSUE_TEMPLATE/bug_report.yml` and `feature_request.yml`, plus + `config.yml` (`blank_issues_enabled: false`). +- `.github/PULL_REQUEST_TEMPLATE.md` with a short checklist. + +## Recommended + +- `CHANGELOG.md` maintained by release-please from Conventional Commits, not by + hand. +- `docs/` with `architecture.md`, `git-workflow.md`, and `release-process.md` + (see `docs-and-context.md`). +- Badges in the README (CI status, license, latest release) once CI exists. +- A CI workflow that runs the stack's quality gates on every PR (see each skill's + `quality-gates.md`). + +## Before the public push + +Run the open-source hard gate in `no-ai-attribution.md`: no AI-tool files, no AI +references anywhere in tree or history, no smart punctuation, human commit author +on every commit, and no secret ever committed (rotate and scrub if one was).