@claude-code-mastery/starter-kit 1.0.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.
- package/.claude/.starter-kit/profiles/clean.md +113 -0
- package/.claude/.starter-kit/profiles/go.md +458 -0
- package/.claude/.starter-kit/profiles/node.md +429 -0
- package/.claude/.starter-kit/profiles/python.md +475 -0
- package/.claude/.starter-kit/shared/analytics-rybbit.md +55 -0
- package/.claude/.starter-kit/shared/claude-md-base.md +93 -0
- package/.claude/.starter-kit/shared/deployment-dokploy.md +158 -0
- package/.claude/.starter-kit/shared/feature-manifest.md +43 -0
- package/.claude/.starter-kit/shared/mcp-and-pooler.md +38 -0
- package/.claude/.starter-kit/shared/mongo-setup.md +20 -0
- package/.claude/.starter-kit/shared/profile-config.md +65 -0
- package/.claude/.starter-kit/shared/seo.md +113 -0
- package/.claude/.starter-kit/shared/sql-setup.md +37 -0
- package/.claude/commands/add-feature.md +349 -0
- package/.claude/commands/add-project-setup.md +156 -0
- package/.claude/commands/architecture.md +27 -0
- package/.claude/commands/commit.md +61 -0
- package/.claude/commands/convert-project-to-starter-kit.md +508 -0
- package/.claude/commands/create-api.md +385 -0
- package/.claude/commands/create-e2e.md +230 -0
- package/.claude/commands/diagram.md +301 -0
- package/.claude/commands/help.md +120 -0
- package/.claude/commands/install-global.md +145 -0
- package/.claude/commands/new-project.md +244 -0
- package/.claude/commands/optimize-docker.md +352 -0
- package/.claude/commands/progress.md +61 -0
- package/.claude/commands/projects-created.md +79 -0
- package/.claude/commands/quickstart.md +105 -0
- package/.claude/commands/refactor.md +267 -0
- package/.claude/commands/remove-project.md +95 -0
- package/.claude/commands/review.md +59 -0
- package/.claude/commands/security-check.md +77 -0
- package/.claude/commands/set-project-profile-default.md +79 -0
- package/.claude/commands/setup.md +337 -0
- package/.claude/commands/show-user-guide.md +58 -0
- package/.claude/commands/starter-kit.md +90 -0
- package/.claude/commands/test-plan.md +118 -0
- package/.claude/commands/update-project.md +413 -0
- package/.claude/commands/what-is-my-ai-doing.md +42 -0
- package/.claude/commands/worktree.md +124 -0
- package/.claude/hooks/block-dangerous-bash.py +55 -0
- package/.claude/hooks/check-branch.sh +116 -0
- package/.claude/hooks/check-e2e.sh +71 -0
- package/.claude/hooks/check-env-sync.sh +41 -0
- package/.claude/hooks/check-file-length.py +47 -0
- package/.claude/hooks/check-ports.sh +59 -0
- package/.claude/hooks/check-rulecatch.sh +33 -0
- package/.claude/hooks/check-rybbit.sh +63 -0
- package/.claude/hooks/lint-on-save.sh +59 -0
- package/.claude/hooks/verify-no-secrets.sh +80 -0
- package/.claude/settings.json +34 -0
- package/.claude/skills/api-conventions/SKILL.md +34 -0
- package/.claude/skills/code-review/SKILL.md +87 -0
- package/.claude/skills/code-review/references/mongodb-checks.md +25 -0
- package/.claude/skills/code-review/references/project-checks.md +38 -0
- package/.claude/skills/create-service/SKILL.md +222 -0
- package/.claude/skills/debugger/SKILL.md +39 -0
- package/.claude/skills/dependency-vetting/SKILL.md +46 -0
- package/.claude/skills/design-review/SKILL.md +50 -0
- package/.claude/skills/mcp-builder/SKILL.md +57 -0
- package/.claude/skills/mongodb-rules/SKILL.md +62 -0
- package/.claude/skills/terminal-tui/SKILL.md +106 -0
- package/.claude/skills/test-writer/SKILL.md +78 -0
- package/LICENSE +21 -0
- package/README.md +2152 -0
- package/bin/cli.js +205 -0
- package/claude-mastery-project.conf +220 -0
- package/global-claude-md/CLAUDE.md +212 -0
- package/global-claude-md/settings.json +3 -0
- package/package.json +81 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a new project with all scaffolding rules applied
|
|
3
|
+
scope: starter-kit
|
|
4
|
+
argument-hint: <path> [profile-or-options...]
|
|
5
|
+
allowed-tools: Bash, Write, Read, AskUserQuestion
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# New Project Scaffold
|
|
9
|
+
|
|
10
|
+
Create a new project with all best practices from the Claude Code Mastery Guides.
|
|
11
|
+
|
|
12
|
+
**Arguments:** $ARGUMENTS
|
|
13
|
+
|
|
14
|
+
## Argument Parsing
|
|
15
|
+
|
|
16
|
+
### Step 0 — Read the config file
|
|
17
|
+
|
|
18
|
+
Before parsing arguments, read `claude-mastery-project.conf` (in the starter kit root or `~/.claude/claude-mastery-project.conf` as fallback).
|
|
19
|
+
|
|
20
|
+
Extract the `[global]` section for `root_dir` and `default_profile`.
|
|
21
|
+
|
|
22
|
+
- `root_dir` — Default parent directory for new projects
|
|
23
|
+
- `default_profile` — Profile to use when no profile is specified in arguments (e.g., `default_profile = clean`). If not set, ask the user as before.
|
|
24
|
+
|
|
25
|
+
### Step 0.0 — Global Claude Config (one-time setup)
|
|
26
|
+
|
|
27
|
+
Check if the user already has the global Claude config installed:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Check if global CLAUDE.md exists
|
|
31
|
+
ls ~/.claude/CLAUDE.md 2>/dev/null
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**If `~/.claude/CLAUDE.md` does NOT exist:**
|
|
35
|
+
- ASK: "You don't have a global CLAUDE.md yet. Want me to install the Claude Code Mastery global config to `~/.claude/`? This sets up security rules, hooks, and standards that apply to ALL your projects. (This is a one-time setup.)"
|
|
36
|
+
- If yes: copy `global-claude-md/CLAUDE.md` → `~/.claude/CLAUDE.md` and `global-claude-md/settings.json` → `~/.claude/settings.json`
|
|
37
|
+
- Also copy hooks: `mkdir -p ~/.claude/hooks && cp .claude/hooks/verify-no-secrets.sh ~/.claude/hooks/`
|
|
38
|
+
|
|
39
|
+
**If `~/.claude/CLAUDE.md` DOES exist:**
|
|
40
|
+
- ASK: "You already have a global CLAUDE.md. Want me to check if the starter kit version has anything new to merge in?"
|
|
41
|
+
- If yes: diff the two files and show what's different. Let the user decide what to merge.
|
|
42
|
+
- If no: skip and continue.
|
|
43
|
+
|
|
44
|
+
**This step typically only happens once.** After the first install, the global config persists across all projects.
|
|
45
|
+
|
|
46
|
+
### Step 0.1 — Resolve the project path
|
|
47
|
+
|
|
48
|
+
The **first argument** is the project name or path. Resolve it using `root_dir`:
|
|
49
|
+
|
|
50
|
+
1. **Explicit path** (starts with `./`, `../`, `~/`, or `/`) → use as-is
|
|
51
|
+
- `/new-project ~/code/my-app` → creates at `~/code/my-app`
|
|
52
|
+
- `/new-project ./my-app` → creates at `./my-app`
|
|
53
|
+
|
|
54
|
+
2. **Just a name** (no path separators) → prepend `root_dir` from `[global]`
|
|
55
|
+
- Config has `root_dir = ~/projects`
|
|
56
|
+
- `/new-project my-app` → creates at `~/projects/my-app`
|
|
57
|
+
- `/new-project tims-api` → creates at `~/projects/tims-api`
|
|
58
|
+
|
|
59
|
+
3. **No argument at all** → ASK the user for the project name, then prepend `root_dir`
|
|
60
|
+
|
|
61
|
+
Everything after the project name/path is shorthand options or a profile name.
|
|
62
|
+
|
|
63
|
+
### Shorthand Arguments (after the path/name)
|
|
64
|
+
|
|
65
|
+
Parse remaining $ARGUMENTS for these keywords:
|
|
66
|
+
|
|
67
|
+
**Profiles:** `clean`, `default`, `api`, `static-site`, `quick`, `enterprise`, `go`, `vue`, `nuxt`, `svelte`, `sveltekit`, `angular`, `python-api`, `django`, `flask` (from `claude-mastery-project.conf`)
|
|
68
|
+
**Special:** `clean` — Claude infrastructure only, zero coding opinions (see Clean Mode below)
|
|
69
|
+
**Languages:** `go`, `golang` (triggers Go scaffolding — see Go Mode below) | `python`, `py` (triggers Python Mode below)
|
|
70
|
+
**Project types:** `webapp`, `api`, `fullstack`, `cli`
|
|
71
|
+
**Frameworks:** `vite`, `react`, `next`, `nextjs`, `astro`, `fastify`, `express`, `hono`, `vue`, `nuxt`, `svelte`, `sveltekit`, `angular`
|
|
72
|
+
**Go Frameworks:** `gin`, `chi`, `echo`, `fiber`, `stdlib`
|
|
73
|
+
**Python Frameworks:** `fastapi`, `django`, `flask`
|
|
74
|
+
**Options:** `seo`, `ssr`, `tailwind`, `prisma`, `docker`, `ci`, `multiregion`
|
|
75
|
+
**Hosting:** `dokploy`, `vercel`, `static`
|
|
76
|
+
**Database:** `mongo`, `postgres`, `mysql`, `mssql`, `sqlite`
|
|
77
|
+
**Analytics:** `rybbit`
|
|
78
|
+
**MCP servers:** `playwright`, `context7`, `rulecatch`
|
|
79
|
+
**NPM extras:** `ai-pooler` (installs @rulecatch/ai-pooler)
|
|
80
|
+
**Package managers:** `pnpm`, `npm`, `bun`
|
|
81
|
+
|
|
82
|
+
Examples:
|
|
83
|
+
- `/new-project my-app` — creates at ~/projects/my-app (from root_dir), asks questions
|
|
84
|
+
- `/new-project my-app clean` — Claude infrastructure only, no coding opinions
|
|
85
|
+
- `/new-project my-app default` — creates at ~/projects/my-app with default profile
|
|
86
|
+
- `/new-project my-app fullstack next seo tailwind pnpm` — ~/projects/my-app, skips all questions
|
|
87
|
+
- `/new-project ./custom-path/my-app api fastify` — explicit path, ignores root_dir
|
|
88
|
+
- `/new-project ~/code/my-app default` — explicit path, uses default profile
|
|
89
|
+
- `/new-project my-app fullstack next mongo playwright context7 rulecatch` — full stack
|
|
90
|
+
- `/new-project my-api go` — Go API with Gin, MongoDB, Docker
|
|
91
|
+
- `/new-project my-api go chi postgres` — Go with Chi, PostgreSQL
|
|
92
|
+
- `/new-project my-cli go cli` — Go CLI with Cobra
|
|
93
|
+
- `/new-project my-app vue` — Vue 3 SPA with Tailwind
|
|
94
|
+
- `/new-project my-app nuxt` — Nuxt full-stack with MongoDB, Docker
|
|
95
|
+
- `/new-project my-app svelte` — Svelte SPA with Tailwind
|
|
96
|
+
- `/new-project my-app sveltekit` — SvelteKit full-stack with MongoDB, Docker
|
|
97
|
+
- `/new-project my-app angular` — Angular SPA with Tailwind
|
|
98
|
+
- `/new-project my-api python-api` — FastAPI with PostgreSQL, Docker
|
|
99
|
+
- `/new-project my-app django` — Django full-stack with PostgreSQL, Docker
|
|
100
|
+
- `/new-project my-api flask` — Flask API with PostgreSQL, Docker
|
|
101
|
+
- `/new-project my-api python fastapi postgres docker` — Python API with overrides
|
|
102
|
+
|
|
103
|
+
Any keyword not provided = check `default_profile` in `[global]` first, then ask the user. If `default_profile` is set (e.g., `default_profile = clean`) and no profile was specified in the arguments, use that profile automatically.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Project Registry — MANDATORY Final Step (ALL modes)
|
|
108
|
+
|
|
109
|
+
**After EVERY successful project scaffold (Clean, Go, Python, or Node.js), register the project in `~/.claude/starter-kit-projects.json`.**
|
|
110
|
+
|
|
111
|
+
This enables `/projects-created` and `/remove-project` to track all projects.
|
|
112
|
+
|
|
113
|
+
### How to register
|
|
114
|
+
|
|
115
|
+
1. Read `~/.claude/starter-kit-projects.json` (create if it doesn't exist)
|
|
116
|
+
2. Append a new entry to the `projects` array:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"name": "my-app",
|
|
121
|
+
"path": "/home/user/projects/my-app",
|
|
122
|
+
"profile": "default",
|
|
123
|
+
"language": "node",
|
|
124
|
+
"framework": "next",
|
|
125
|
+
"database": "mongo",
|
|
126
|
+
"createdAt": "2025-01-15T10:30:00Z"
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
3. Write the updated file back
|
|
131
|
+
|
|
132
|
+
**Field mapping:**
|
|
133
|
+
- `name` — project directory name (last segment of path)
|
|
134
|
+
- `path` — absolute path to the project directory
|
|
135
|
+
- `profile` — profile name used (e.g., `clean`, `default`, `go`, `python-api`), or `custom` if built from shorthand args
|
|
136
|
+
- `language` — `node`, `go`, or `python`
|
|
137
|
+
- `framework` — the chosen framework (e.g., `next`, `gin`, `fastapi`), or `none` for clean mode
|
|
138
|
+
- `database` — `mongo`, `postgres`, `mysql`, `mssql`, `sqlite`, or `none`
|
|
139
|
+
- `createdAt` — ISO 8601 timestamp of creation
|
|
140
|
+
|
|
141
|
+
**If the file doesn't exist yet**, create it with:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"projects": []
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**This step happens AFTER git init and initial commit, as the very last action before displaying the verification checklist.**
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Route to the Profile
|
|
157
|
+
|
|
158
|
+
The detailed scaffolding lives in `.claude/.starter-kit/`, split so only the parts a run actually needs are loaded. Based on the resolved mode/language, read the matching profile file and follow it exactly:
|
|
159
|
+
|
|
160
|
+
| Mode / language | Read and follow |
|
|
161
|
+
| --- | --- |
|
|
162
|
+
| `clean` | `.claude/.starter-kit/profiles/clean.md` |
|
|
163
|
+
| `go` / `golang` / `gin`, `chi`, `echo`, `fiber`, `stdlib` | `.claude/.starter-kit/profiles/go.md` |
|
|
164
|
+
| `python` / `py` / `fastapi`, `django`, `flask` | `.claude/.starter-kit/profiles/python.md` |
|
|
165
|
+
| default / `node` / any JS-TS framework | `.claude/.starter-kit/profiles/node.md` |
|
|
166
|
+
|
|
167
|
+
Read exactly one profile, the one the mode/language resolves to. Do NOT read the others.
|
|
168
|
+
|
|
169
|
+
`.claude/.starter-kit/` is kit-internal scaffolding source. It is read while running `/new-project`, but it is **never copied into the scaffolded project** (the new project doesn't have `/new-project`). Copy only `skills/`, `hooks/`, `settings.json`, and `scope: project` commands, as the steps below specify.
|
|
170
|
+
|
|
171
|
+
Every profile except `clean` builds its CLAUDE.md from `.claude/.starter-kit/shared/claude-md-base.md` plus its own rules; read the base first. For `clean`, the base *is* the CLAUDE.md.
|
|
172
|
+
|
|
173
|
+
## Load Only the Shared Modules the Choices Require
|
|
174
|
+
|
|
175
|
+
After the profile, read only the shared modules the user's selections call for, nothing more:
|
|
176
|
+
|
|
177
|
+
| If the user selected | Also read and apply |
|
|
178
|
+
| --- | --- |
|
|
179
|
+
| a SQL database (`postgres`, `mysql`, `mssql`, `sqlite`) | `.claude/.starter-kit/shared/sql-setup.md` |
|
|
180
|
+
| `mongo` | `.claude/.starter-kit/shared/mongo-setup.md` |
|
|
181
|
+
| a web (HTML-serving) project | `.claude/.starter-kit/shared/seo.md` |
|
|
182
|
+
| Dokploy hosting | `.claude/.starter-kit/shared/deployment-dokploy.md` |
|
|
183
|
+
| Rybbit analytics | `.claude/.starter-kit/shared/analytics-rybbit.md` |
|
|
184
|
+
| MCP servers or AI-Pooler | `.claude/.starter-kit/shared/mcp-and-pooler.md` |
|
|
185
|
+
|
|
186
|
+
Profile presets (the `claude-mastery-project.conf` format) are documented in `.claude/.starter-kit/shared/profile-config.md`; read it only when creating or resolving a profile.
|
|
187
|
+
|
|
188
|
+
**Example:** a `node` + `mongo` run reads `profiles/node.md`, `shared/claude-md-base.md`, `shared/mongo-setup.md`, and `shared/seo.md`. It never loads `go.md` or `python.md`.
|
|
189
|
+
|
|
190
|
+
## Feature Manifest — MANDATORY Final Step (ALL modes except Clean)
|
|
191
|
+
|
|
192
|
+
Follow `.claude/.starter-kit/shared/feature-manifest.md` to map the scaffolding choices to features and write the project's feature manifest.
|
|
193
|
+
|
|
194
|
+
## Verification Checklist
|
|
195
|
+
|
|
196
|
+
After creation, verify and report:
|
|
197
|
+
|
|
198
|
+
**Core files:**
|
|
199
|
+
- [ ] .env exists (empty)
|
|
200
|
+
- [ ] .env.example exists (with placeholders)
|
|
201
|
+
- [ ] .gitignore includes all required entries
|
|
202
|
+
- [ ] .dockerignore exists
|
|
203
|
+
- [ ] CLAUDE.md has all required sections (overview, stack, commands, ports)
|
|
204
|
+
- [ ] package.json has ALL required scripts (dev, build, test, test:e2e, test:kill-ports)
|
|
205
|
+
- [ ] Error handlers in entry point (gracefulShutdown for StrictDB projects)
|
|
206
|
+
- [ ] TypeScript strict mode enabled
|
|
207
|
+
|
|
208
|
+
**Testing:**
|
|
209
|
+
- [ ] vitest.config.ts created and configured
|
|
210
|
+
- [ ] playwright.config.ts created with test ports (4000/4010/4020) and webServer
|
|
211
|
+
- [ ] test:kill-ports script kills test ports BEFORE E2E runs
|
|
212
|
+
- [ ] tests/e2e/ directory exists
|
|
213
|
+
- [ ] tests/unit/ directory exists
|
|
214
|
+
- [ ] Example E2E test has minimum 3 assertions (URL, element, data)
|
|
215
|
+
- [ ] `pnpm test` runs unit + E2E in sequence
|
|
216
|
+
|
|
217
|
+
**Web projects:**
|
|
218
|
+
- [ ] SEO meta tags in layout/head
|
|
219
|
+
- [ ] JSON-LD structured data included
|
|
220
|
+
- [ ] robots.txt created
|
|
221
|
+
|
|
222
|
+
**Infrastructure:**
|
|
223
|
+
- [ ] Dockerfile with multi-stage build (Docker projects)
|
|
224
|
+
- [ ] scripts/deploy.sh created (Dokploy projects)
|
|
225
|
+
- [ ] Multi-region deploy script (if multiregion selected)
|
|
226
|
+
|
|
227
|
+
**Database (StrictDB projects):**
|
|
228
|
+
- [ ] StrictDB installed as dependency
|
|
229
|
+
- [ ] scripts/db-query.ts — Test Query Master
|
|
230
|
+
- [ ] scripts/queries/ directory
|
|
231
|
+
- [ ] db-query rules in CLAUDE.md
|
|
232
|
+
|
|
233
|
+
**Content (if web project with articles/posts):**
|
|
234
|
+
- [ ] scripts/build-content.ts
|
|
235
|
+
- [ ] scripts/content.config.json
|
|
236
|
+
- [ ] content/ directory
|
|
237
|
+
|
|
238
|
+
**Extras:**
|
|
239
|
+
- [ ] MCP servers installed (if selected)
|
|
240
|
+
- [ ] claude-mastery-project.conf created (if using profiles)
|
|
241
|
+
- [ ] No file > 300 lines
|
|
242
|
+
- [ ] All independent awaits use Promise.all
|
|
243
|
+
|
|
244
|
+
Report any missing items.
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Analyze and optimize Docker builds for production
|
|
3
|
+
scope: project
|
|
4
|
+
argument-hint: [dockerfile-path]
|
|
5
|
+
allowed-tools: Read, Write, Edit, Grep, Glob, Bash
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Optimize Docker Build
|
|
9
|
+
|
|
10
|
+
Analyze and optimize the Docker setup for: **$ARGUMENTS**
|
|
11
|
+
|
|
12
|
+
If no Dockerfile path provided, search for Dockerfiles in the project root.
|
|
13
|
+
|
|
14
|
+
## Step 0 — Auto-Branch (if on main)
|
|
15
|
+
|
|
16
|
+
Before modifying any files, check the current branch:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git branch --show-current
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Default behavior** (`auto_branch = true` in `claude-mastery-project.conf`):
|
|
23
|
+
- If on `main` or `master`: automatically create a feature branch and switch to it:
|
|
24
|
+
```bash
|
|
25
|
+
git checkout -b chore/docker-optimize
|
|
26
|
+
```
|
|
27
|
+
Report: "Created branch `chore/docker-optimize` — main stays untouched."
|
|
28
|
+
- If already on a feature branch: proceed
|
|
29
|
+
- If not a git repo: skip this check
|
|
30
|
+
|
|
31
|
+
**To disable:** Set `auto_branch = false` in `claude-mastery-project.conf`. When disabled, warn and ask the user before proceeding on main.
|
|
32
|
+
|
|
33
|
+
## Step 1 — Find and Read All Docker Files
|
|
34
|
+
|
|
35
|
+
Read these files (if they exist):
|
|
36
|
+
- `Dockerfile` (or the path provided in $ARGUMENTS)
|
|
37
|
+
- `docker-compose.yml` / `docker-compose.yaml`
|
|
38
|
+
- `.dockerignore`
|
|
39
|
+
- `package.json` (for build scripts and dependencies)
|
|
40
|
+
|
|
41
|
+
## Step 2 — Audit Against Best Practices
|
|
42
|
+
|
|
43
|
+
Check every rule below. For each violation, report:
|
|
44
|
+
- What's wrong
|
|
45
|
+
- Why it matters (performance impact or security risk)
|
|
46
|
+
- The fix
|
|
47
|
+
|
|
48
|
+
### RULE 1: Multi-Stage Builds (MANDATORY)
|
|
49
|
+
|
|
50
|
+
Every production Dockerfile MUST use multi-stage builds. No exceptions.
|
|
51
|
+
|
|
52
|
+
```dockerfile
|
|
53
|
+
# CORRECT — multi-stage: build artifacts don't ship to production
|
|
54
|
+
FROM node:20-alpine AS builder
|
|
55
|
+
WORKDIR /app
|
|
56
|
+
COPY package.json pnpm-lock.yaml ./
|
|
57
|
+
RUN corepack enable && pnpm install --frozen-lockfile
|
|
58
|
+
COPY . .
|
|
59
|
+
RUN pnpm build
|
|
60
|
+
|
|
61
|
+
FROM node:20-alpine AS runner
|
|
62
|
+
WORKDIR /app
|
|
63
|
+
COPY --from=builder /app/dist ./dist
|
|
64
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
65
|
+
COPY --from=builder /app/package.json ./
|
|
66
|
+
CMD ["node", "dist/index.js"]
|
|
67
|
+
|
|
68
|
+
# WRONG — single stage ships devDependencies, source code, build tools
|
|
69
|
+
FROM node:20
|
|
70
|
+
WORKDIR /app
|
|
71
|
+
COPY . .
|
|
72
|
+
RUN npm install
|
|
73
|
+
RUN npm run build
|
|
74
|
+
CMD ["node", "dist/index.js"]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Why:** Single-stage images are 3-10x larger. They ship TypeScript source, devDependencies, build tools — none of which are needed at runtime.
|
|
78
|
+
|
|
79
|
+
### RULE 2: Layer Caching — COPY package.json FIRST
|
|
80
|
+
|
|
81
|
+
```dockerfile
|
|
82
|
+
# CORRECT — package.json copied before source (cached unless deps change)
|
|
83
|
+
COPY package.json pnpm-lock.yaml ./
|
|
84
|
+
RUN pnpm install --frozen-lockfile
|
|
85
|
+
COPY . .
|
|
86
|
+
|
|
87
|
+
# WRONG — any source change busts the install cache
|
|
88
|
+
COPY . .
|
|
89
|
+
RUN pnpm install
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Why:** Docker caches layers top-down. If `package.json` hasn't changed, the `install` layer is cached. Copying all files first means every code change re-installs all dependencies.
|
|
93
|
+
|
|
94
|
+
### RULE 3: Use Alpine Base Images
|
|
95
|
+
|
|
96
|
+
```dockerfile
|
|
97
|
+
# CORRECT — alpine is ~50MB
|
|
98
|
+
FROM node:20-alpine
|
|
99
|
+
|
|
100
|
+
# WRONG — full image is ~350MB
|
|
101
|
+
FROM node:20
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Why:** Alpine is 7x smaller. Less attack surface, faster pulls, smaller registry storage.
|
|
105
|
+
|
|
106
|
+
### RULE 4: Non-Root User
|
|
107
|
+
|
|
108
|
+
```dockerfile
|
|
109
|
+
# CORRECT — run as non-root
|
|
110
|
+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
111
|
+
USER appuser
|
|
112
|
+
|
|
113
|
+
# WRONG — running as root
|
|
114
|
+
CMD ["node", "dist/index.js"]
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Why:** Running as root inside a container means a container escape gives root on the host. Always drop privileges.
|
|
118
|
+
|
|
119
|
+
### RULE 5: .dockerignore Exists and Is Complete
|
|
120
|
+
|
|
121
|
+
Must include at minimum:
|
|
122
|
+
```
|
|
123
|
+
.env
|
|
124
|
+
.env.*
|
|
125
|
+
.git/
|
|
126
|
+
node_modules/
|
|
127
|
+
dist/
|
|
128
|
+
coverage/
|
|
129
|
+
test-results/
|
|
130
|
+
playwright-report/
|
|
131
|
+
.claude/
|
|
132
|
+
CLAUDE.local.md
|
|
133
|
+
*.log
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Why:** Without `.dockerignore`, `COPY . .` sends `.git/` (huge), `node_modules/` (reinstalled anyway), `.env` (secrets!), and test artifacts into the build context.
|
|
137
|
+
|
|
138
|
+
### RULE 6: Frozen Lockfile for Installs
|
|
139
|
+
|
|
140
|
+
```dockerfile
|
|
141
|
+
# CORRECT — deterministic installs
|
|
142
|
+
RUN pnpm install --frozen-lockfile
|
|
143
|
+
RUN npm ci
|
|
144
|
+
|
|
145
|
+
# WRONG — may resolve different versions
|
|
146
|
+
RUN pnpm install
|
|
147
|
+
RUN npm install
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Why:** `install` can resolve newer patch versions than what was tested. `--frozen-lockfile` / `ci` ensures exact versions from the lockfile.
|
|
151
|
+
|
|
152
|
+
### RULE 7: Explicit EXPOSE
|
|
153
|
+
|
|
154
|
+
```dockerfile
|
|
155
|
+
# CORRECT — documents the port
|
|
156
|
+
EXPOSE 3001
|
|
157
|
+
CMD ["node", "dist/index.js"]
|
|
158
|
+
|
|
159
|
+
# WRONG — no EXPOSE
|
|
160
|
+
CMD ["node", "dist/index.js"]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Why:** `EXPOSE` documents which ports the container listens on. Required for Docker networking and orchestrators.
|
|
164
|
+
|
|
165
|
+
### RULE 8: No Secrets in Build Args (for runtime secrets)
|
|
166
|
+
|
|
167
|
+
```dockerfile
|
|
168
|
+
# CORRECT — runtime secrets via environment
|
|
169
|
+
ENV DATABASE_URL=""
|
|
170
|
+
# Set at runtime: docker run -e DATABASE_URL=...
|
|
171
|
+
|
|
172
|
+
# WRONG — baked into image layer
|
|
173
|
+
ARG DATABASE_URL
|
|
174
|
+
RUN echo $DATABASE_URL > /app/.env
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Exception:** `NEXT_PUBLIC_*` variables for Next.js MUST be build args (they're baked into the JS bundle at build time). This is expected and safe — they're public values.
|
|
178
|
+
|
|
179
|
+
### RULE 9: Health Check
|
|
180
|
+
|
|
181
|
+
```dockerfile
|
|
182
|
+
# CORRECT — Docker knows if the app is healthy
|
|
183
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
|
184
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Why:** Without HEALTHCHECK, Docker considers the container healthy as long as the process is running — even if it's deadlocked or returning 500s.
|
|
188
|
+
|
|
189
|
+
### RULE 10: Minimize Layers
|
|
190
|
+
|
|
191
|
+
```dockerfile
|
|
192
|
+
# CORRECT — single RUN for related commands
|
|
193
|
+
RUN corepack enable && \
|
|
194
|
+
corepack prepare pnpm@latest --activate && \
|
|
195
|
+
pnpm install --frozen-lockfile
|
|
196
|
+
|
|
197
|
+
# WRONG — each RUN creates a layer
|
|
198
|
+
RUN corepack enable
|
|
199
|
+
RUN corepack prepare pnpm@latest --activate
|
|
200
|
+
RUN pnpm install --frozen-lockfile
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Why:** Each `RUN` creates a cached layer. Fewer layers = smaller image and faster builds.
|
|
204
|
+
|
|
205
|
+
### RULE 11: Production-Only Dependencies in Runner
|
|
206
|
+
|
|
207
|
+
```dockerfile
|
|
208
|
+
# CORRECT — only production deps in final image
|
|
209
|
+
FROM node:20-alpine AS runner
|
|
210
|
+
COPY --from=builder /app/package.json ./
|
|
211
|
+
RUN pnpm install --prod --frozen-lockfile
|
|
212
|
+
|
|
213
|
+
# OR: prune in builder stage
|
|
214
|
+
FROM node:20-alpine AS builder
|
|
215
|
+
RUN pnpm install --frozen-lockfile
|
|
216
|
+
RUN pnpm build
|
|
217
|
+
RUN pnpm prune --prod
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Why:** devDependencies (TypeScript, Vitest, Playwright, tsx) are only needed for building. Shipping them adds 100-500MB to the final image.
|
|
221
|
+
|
|
222
|
+
### RULE 12: Pin Major Versions
|
|
223
|
+
|
|
224
|
+
```dockerfile
|
|
225
|
+
# CORRECT — predictable
|
|
226
|
+
FROM node:20-alpine
|
|
227
|
+
|
|
228
|
+
# WRONG — could be 20, 22, 24 tomorrow
|
|
229
|
+
FROM node:alpine
|
|
230
|
+
FROM node:latest
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Why:** `latest` or unversioned tags change without notice. Your build may suddenly break on a Node.js major version bump.
|
|
234
|
+
|
|
235
|
+
## Step 3 — Generate Optimized Dockerfile
|
|
236
|
+
|
|
237
|
+
If the current Dockerfile violates any rules above, generate a corrected version.
|
|
238
|
+
|
|
239
|
+
Use this template as a starting point:
|
|
240
|
+
|
|
241
|
+
```dockerfile
|
|
242
|
+
# ============================================
|
|
243
|
+
# Stage 1: Build
|
|
244
|
+
# ============================================
|
|
245
|
+
FROM node:20-alpine AS builder
|
|
246
|
+
WORKDIR /app
|
|
247
|
+
|
|
248
|
+
# Enable pnpm
|
|
249
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
250
|
+
|
|
251
|
+
# Install dependencies (cached unless package.json changes)
|
|
252
|
+
COPY package.json pnpm-lock.yaml ./
|
|
253
|
+
RUN pnpm install --frozen-lockfile
|
|
254
|
+
|
|
255
|
+
# Build args for public env vars (Next.js only)
|
|
256
|
+
# ARG NEXT_PUBLIC_RYBBIT_SITE_ID
|
|
257
|
+
# ARG NEXT_PUBLIC_RYBBIT_URL
|
|
258
|
+
|
|
259
|
+
# Copy source and build
|
|
260
|
+
COPY . .
|
|
261
|
+
RUN pnpm build
|
|
262
|
+
|
|
263
|
+
# Prune dev dependencies
|
|
264
|
+
RUN pnpm prune --prod
|
|
265
|
+
|
|
266
|
+
# ============================================
|
|
267
|
+
# Stage 2: Production
|
|
268
|
+
# ============================================
|
|
269
|
+
FROM node:20-alpine AS runner
|
|
270
|
+
WORKDIR /app
|
|
271
|
+
|
|
272
|
+
# Non-root user
|
|
273
|
+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
274
|
+
|
|
275
|
+
# Copy only what's needed
|
|
276
|
+
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
|
|
277
|
+
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
|
|
278
|
+
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
|
|
279
|
+
|
|
280
|
+
# Runtime config
|
|
281
|
+
ENV NODE_ENV=production
|
|
282
|
+
EXPOSE 3001
|
|
283
|
+
|
|
284
|
+
# Health check
|
|
285
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
|
286
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1
|
|
287
|
+
|
|
288
|
+
USER appuser
|
|
289
|
+
CMD ["node", "dist/index.js"]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Step 4 — Verify .dockerignore
|
|
293
|
+
|
|
294
|
+
If `.dockerignore` is missing or incomplete, create/update it with all required entries.
|
|
295
|
+
|
|
296
|
+
## Step 5 — Docker Local Test Gate (if enabled)
|
|
297
|
+
|
|
298
|
+
Check `claude-mastery-project.conf` for `docker_test_before_push`:
|
|
299
|
+
|
|
300
|
+
**When `docker_test_before_push = true`:**
|
|
301
|
+
|
|
302
|
+
Before ANY `docker push` is allowed, you MUST run this verification sequence. If any step fails, STOP and fix the issue — do NOT push.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# 1. Build the image
|
|
306
|
+
docker build -t $IMAGE_NAME .
|
|
307
|
+
|
|
308
|
+
# 2. Run container locally
|
|
309
|
+
docker run -d -p 3001:3001 --name test-container $IMAGE_NAME
|
|
310
|
+
|
|
311
|
+
# 3. Wait for startup
|
|
312
|
+
sleep 5
|
|
313
|
+
|
|
314
|
+
# 4. Verify container is still running (didn't crash)
|
|
315
|
+
docker ps --filter "name=test-container" --filter "status=running" -q
|
|
316
|
+
|
|
317
|
+
# 5. Check health endpoint responds
|
|
318
|
+
curl -sf http://localhost:3001/health || echo "HEALTH CHECK FAILED"
|
|
319
|
+
|
|
320
|
+
# 6. Check container logs for fatal errors
|
|
321
|
+
docker logs test-container 2>&1 | grep -iE "(error|fatal|exception|ENOENT|cannot find)" && echo "ERRORS FOUND IN LOGS"
|
|
322
|
+
|
|
323
|
+
# 7. Clean up test container
|
|
324
|
+
docker stop test-container && docker rm test-container
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Pass criteria — ALL must be true:**
|
|
328
|
+
- Container is still running after 5 seconds (didn't exit with error)
|
|
329
|
+
- Health endpoint returns HTTP 200
|
|
330
|
+
- No fatal errors in container logs
|
|
331
|
+
|
|
332
|
+
**If any check fails:** Report exactly what failed, show the logs, and do NOT push. Fix the issue first.
|
|
333
|
+
|
|
334
|
+
**When `docker_test_before_push = false` (default):** Skip this step. The user manages their own testing.
|
|
335
|
+
|
|
336
|
+
This gate applies to ALL docker push operations, not just `/optimize-docker`. Any command or workflow that pushes to Docker Hub must check this setting first.
|
|
337
|
+
|
|
338
|
+
## Step 6 — RuleCatch Report
|
|
339
|
+
|
|
340
|
+
After all changes are complete, check RuleCatch:
|
|
341
|
+
|
|
342
|
+
- If the RuleCatch MCP server is available: query for violations in the modified Docker files
|
|
343
|
+
- Report any violations found
|
|
344
|
+
- If no MCP: suggest checking the RuleCatch dashboard
|
|
345
|
+
|
|
346
|
+
## Step 7 — Report
|
|
347
|
+
|
|
348
|
+
Output a summary:
|
|
349
|
+
- Image size estimate (before vs after)
|
|
350
|
+
- Number of violations found and fixed
|
|
351
|
+
- Layer count (before vs after)
|
|
352
|
+
- Security improvements made
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show project progress — what's done, what's pending, what's next
|
|
3
|
+
scope: project
|
|
4
|
+
allowed-tools: Read, Bash(find:*), Bash(ls:*), Bash(wc:*), Bash(git log:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Project Progress
|
|
8
|
+
|
|
9
|
+
Check the actual state of all components and report status.
|
|
10
|
+
|
|
11
|
+
## Instructions
|
|
12
|
+
|
|
13
|
+
1. Read `project-docs/ARCHITECTURE.md` for project context (if it exists)
|
|
14
|
+
2. Check the `src/` directory structure
|
|
15
|
+
3. Check the `tests/` directory for test coverage
|
|
16
|
+
4. Check recent git activity
|
|
17
|
+
|
|
18
|
+
## Shell Commands to Run
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
echo "=== Source Files ==="
|
|
22
|
+
find src/ -name "*.ts" -o -name "*.tsx" | head -30 2>/dev/null || echo "No src/ directory"
|
|
23
|
+
|
|
24
|
+
echo ""
|
|
25
|
+
echo "=== Test Files ==="
|
|
26
|
+
find tests/ -name "*.test.*" -o -name "*.spec.*" | head -30 2>/dev/null || echo "No test files"
|
|
27
|
+
|
|
28
|
+
echo ""
|
|
29
|
+
echo "=== Recent Activity (Last 7 Days) ==="
|
|
30
|
+
git log --oneline --since="7 days ago" 2>/dev/null | head -15 || echo "No recent commits"
|
|
31
|
+
|
|
32
|
+
echo ""
|
|
33
|
+
echo "=== File Count by Type ==="
|
|
34
|
+
find src/ -name "*.ts" 2>/dev/null | wc -l | xargs -I{} echo "TypeScript: {} files"
|
|
35
|
+
find src/ -name "*.js" 2>/dev/null | wc -l | xargs -I{} echo "JavaScript: {} files"
|
|
36
|
+
find tests/ -name "*.test.*" 2>/dev/null | wc -l | xargs -I{} echo "Tests: {} files"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Output Format
|
|
40
|
+
|
|
41
|
+
| Area | Files | Status | Notes |
|
|
42
|
+
|------|-------|--------|-------|
|
|
43
|
+
| Source code | N files | ... | ... |
|
|
44
|
+
| Tests | N files | ... | ... |
|
|
45
|
+
| Documentation | ... | ... | ... |
|
|
46
|
+
|
|
47
|
+
### RuleCatch Report
|
|
48
|
+
| Metric | Value |
|
|
49
|
+
|--------|-------|
|
|
50
|
+
| Violations (this session) | ... |
|
|
51
|
+
| Critical violations | ... |
|
|
52
|
+
| Most violated rule | ... |
|
|
53
|
+
| Files with violations | ... |
|
|
54
|
+
|
|
55
|
+
If the RuleCatch MCP server is available: query for session summary and populate the table above.
|
|
56
|
+
If no MCP available: show "Install RuleCatch for violation tracking — `npx @rulecatch/mcp-server init`"
|
|
57
|
+
|
|
58
|
+
### Next Actions (Priority Order)
|
|
59
|
+
1. ...
|
|
60
|
+
2. ...
|
|
61
|
+
3. ...
|