cc-starter 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/LICENSE +21 -0
- package/README.md +149 -0
- package/bin/cc-starter.js +55 -0
- package/lib/constants.js +32 -0
- package/lib/detect.js +109 -0
- package/lib/plugins.js +74 -0
- package/lib/scaffold.js +261 -0
- package/lib/wizard.js +99 -0
- package/package.json +30 -0
- package/template/CLAUDE.md.hbs +44 -0
- package/template/claude/commands/kickstart.md +16 -0
- package/template/claude/memory/MEMORY.md +11 -0
- package/template/claude/project/README.md +7 -0
- package/template/claude/reference/README.md +7 -0
- package/template/claude/rules/01-general.md +36 -0
- package/template/claude/rules/02-code-standards.md +23 -0
- package/template/claude/rules/03-dev-ops.md +20 -0
- package/template/claude/settings.json +4 -0
- package/template/scripts/stats/cocomo.js +178 -0
- package/template/scripts/stats/project-report.js +640 -0
- package/template/scripts/stats/vibe-code.js +533 -0
- package/template/scripts/stats/vibe-stats.js +249 -0
package/lib/scaffold.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import Handlebars from 'handlebars';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const TEMPLATE_DIR = path.join(__dirname, '..', 'template');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Scaffold a cc-starter project into the given directory.
|
|
13
|
+
* @param {object} config - Wizard output
|
|
14
|
+
* @param {string} [cwd=process.cwd()] - Target directory
|
|
15
|
+
* @returns {Promise<{ filesCreated: number, filesSkipped: number }>}
|
|
16
|
+
*/
|
|
17
|
+
export async function scaffold(config, cwd = process.cwd()) {
|
|
18
|
+
let filesCreated = 0;
|
|
19
|
+
let filesSkipped = 0;
|
|
20
|
+
|
|
21
|
+
// ── 1. .claude/ directory structure ────────────────────────────────
|
|
22
|
+
const claudeDir = path.join(cwd, '.claude');
|
|
23
|
+
const claudeExists = fs.existsSync(claudeDir);
|
|
24
|
+
|
|
25
|
+
let claudeAction = 'overwrite';
|
|
26
|
+
if (claudeExists) {
|
|
27
|
+
const answer = await inquirer.prompt([{
|
|
28
|
+
type: 'list',
|
|
29
|
+
name: 'action',
|
|
30
|
+
message: 'Existing .claude/ found. What should we do?',
|
|
31
|
+
choices: [
|
|
32
|
+
{ name: 'Overwrite — replace all files', value: 'overwrite' },
|
|
33
|
+
{ name: 'Merge — keep existing, add missing files only', value: 'merge' },
|
|
34
|
+
{ name: 'Skip — leave .claude/ untouched', value: 'skip' }
|
|
35
|
+
]
|
|
36
|
+
}]);
|
|
37
|
+
claudeAction = answer.action;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (claudeAction === 'skip') {
|
|
41
|
+
console.log(chalk.yellow(' ⊘ .claude/') + chalk.dim(' skipped'));
|
|
42
|
+
filesSkipped += countFiles(path.join(TEMPLATE_DIR, 'claude'));
|
|
43
|
+
} else {
|
|
44
|
+
const result = copyClaudeDir(claudeAction, cwd);
|
|
45
|
+
filesCreated += result.created;
|
|
46
|
+
filesSkipped += result.skipped;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── 2. Render CLAUDE.md from Handlebars template ──────────────────
|
|
50
|
+
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
51
|
+
const claudeMdExists = fs.existsSync(claudeMdPath);
|
|
52
|
+
|
|
53
|
+
let claudeMdAction = 'overwrite';
|
|
54
|
+
if (claudeMdExists) {
|
|
55
|
+
const answer = await inquirer.prompt([{
|
|
56
|
+
type: 'list',
|
|
57
|
+
name: 'action',
|
|
58
|
+
message: 'Existing CLAUDE.md found. What should we do?',
|
|
59
|
+
choices: [
|
|
60
|
+
{ name: 'Overwrite — replace with cc-starter version', value: 'overwrite' },
|
|
61
|
+
{ name: 'Append — add cc-starter section at the end', value: 'append' },
|
|
62
|
+
{ name: 'Skip — leave CLAUDE.md untouched', value: 'skip' }
|
|
63
|
+
]
|
|
64
|
+
}]);
|
|
65
|
+
claudeMdAction = answer.action;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (claudeMdAction === 'skip') {
|
|
69
|
+
console.log(chalk.yellow(' ⊘ CLAUDE.md') + chalk.dim(' skipped'));
|
|
70
|
+
filesSkipped += 1;
|
|
71
|
+
} else {
|
|
72
|
+
renderClaudeMd(config, claudeMdAction, cwd);
|
|
73
|
+
filesCreated += 1;
|
|
74
|
+
console.log(chalk.green(' ✓ CLAUDE.md') + chalk.dim(` ${claudeMdAction === 'append' ? 'appended' : 'created'}`));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ── 3. Copy scripts/stats/ (always overwrite) ─────────────────────
|
|
78
|
+
const scriptsResult = copyScriptsStats(cwd);
|
|
79
|
+
filesCreated += scriptsResult.created;
|
|
80
|
+
console.log(chalk.green(' ✓ scripts/stats/') + chalk.dim(` ${scriptsResult.created} files`));
|
|
81
|
+
|
|
82
|
+
// ── 4. Create .cc-starter.json (always overwrite) ──────────────────
|
|
83
|
+
const ccConfig = {
|
|
84
|
+
projectName: config.projectName,
|
|
85
|
+
hourlyRate: config.hourlyRate,
|
|
86
|
+
reportStyle: config.reportStyle,
|
|
87
|
+
createdAt: new Date().toISOString(),
|
|
88
|
+
version: '1.0.0'
|
|
89
|
+
};
|
|
90
|
+
fs.writeJsonSync(path.join(cwd, '.cc-starter.json'), ccConfig, { spaces: 2 });
|
|
91
|
+
filesCreated += 1;
|
|
92
|
+
console.log(chalk.green(' ✓ .cc-starter.json') + chalk.dim(' created'));
|
|
93
|
+
|
|
94
|
+
// ── 5. Update .gitignore ───────────────────────────────────────────
|
|
95
|
+
const gitignoreUpdated = updateGitignore(cwd);
|
|
96
|
+
if (gitignoreUpdated) {
|
|
97
|
+
filesCreated += 1;
|
|
98
|
+
console.log(chalk.green(' ✓ .gitignore') + chalk.dim(' updated'));
|
|
99
|
+
} else {
|
|
100
|
+
console.log(chalk.dim(' - .gitignore already up to date'));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log();
|
|
104
|
+
console.log(chalk.bold.green(` Done!`) + chalk.dim(` ${filesCreated} created, ${filesSkipped} skipped`));
|
|
105
|
+
|
|
106
|
+
return { filesCreated, filesSkipped };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Copy the template/claude/ tree into cwd/.claude/.
|
|
113
|
+
* In 'merge' mode, only copies files that don't already exist.
|
|
114
|
+
*/
|
|
115
|
+
function copyClaudeDir(action, cwd) {
|
|
116
|
+
const src = path.join(TEMPLATE_DIR, 'claude');
|
|
117
|
+
const dest = path.join(cwd, '.claude');
|
|
118
|
+
let created = 0;
|
|
119
|
+
let skipped = 0;
|
|
120
|
+
|
|
121
|
+
const subdirs = [
|
|
122
|
+
{ dir: 'rules', files: ['01-general.md', '02-code-standards.md', '03-dev-ops.md'] },
|
|
123
|
+
{ dir: 'memory', files: ['MEMORY.md'] },
|
|
124
|
+
{ dir: 'project', files: ['README.md'] },
|
|
125
|
+
{ dir: 'reference', files: ['README.md'] },
|
|
126
|
+
{ dir: 'commands', files: ['kickstart.md'] },
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
// Also copy settings.json at the root of .claude/
|
|
130
|
+
const rootFiles = ['settings.json'];
|
|
131
|
+
|
|
132
|
+
for (const { dir, files } of subdirs) {
|
|
133
|
+
const destDir = path.join(dest, dir);
|
|
134
|
+
fs.ensureDirSync(destDir);
|
|
135
|
+
let dirCreated = 0;
|
|
136
|
+
|
|
137
|
+
for (const file of files) {
|
|
138
|
+
const srcFile = path.join(src, dir, file);
|
|
139
|
+
const destFile = path.join(destDir, file);
|
|
140
|
+
|
|
141
|
+
if (action === 'merge' && fs.existsSync(destFile)) {
|
|
142
|
+
skipped += 1;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
fs.copySync(srcFile, destFile);
|
|
147
|
+
dirCreated += 1;
|
|
148
|
+
created += 1;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (dirCreated > 0) {
|
|
152
|
+
console.log(chalk.green(` ✓ .claude/${dir}/`) + chalk.dim(` ${dirCreated} file${dirCreated !== 1 ? 's' : ''}`));
|
|
153
|
+
} else {
|
|
154
|
+
console.log(chalk.yellow(` ⊘ .claude/${dir}/`) + chalk.dim(' skipped (exists)'));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (const file of rootFiles) {
|
|
159
|
+
const srcFile = path.join(src, file);
|
|
160
|
+
const destFile = path.join(dest, file);
|
|
161
|
+
|
|
162
|
+
if (action === 'merge' && fs.existsSync(destFile)) {
|
|
163
|
+
skipped += 1;
|
|
164
|
+
console.log(chalk.yellow(` ⊘ .claude/${file}`) + chalk.dim(' skipped (exists)'));
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
fs.copySync(srcFile, destFile);
|
|
169
|
+
created += 1;
|
|
170
|
+
console.log(chalk.green(` ✓ .claude/${file}`) + chalk.dim(' created'));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return { created, skipped };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Render CLAUDE.md from Handlebars template.
|
|
178
|
+
*/
|
|
179
|
+
function renderClaudeMd(config, action, cwd) {
|
|
180
|
+
const templateSrc = fs.readFileSync(path.join(TEMPLATE_DIR, 'CLAUDE.md.hbs'), 'utf-8');
|
|
181
|
+
const template = Handlebars.compile(templateSrc);
|
|
182
|
+
|
|
183
|
+
const techStack = config.techStack || { languages: [], frameworks: [] };
|
|
184
|
+
const rendered = template({
|
|
185
|
+
projectName: config.projectName,
|
|
186
|
+
techStack
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const destPath = path.join(cwd, 'CLAUDE.md');
|
|
190
|
+
|
|
191
|
+
if (action === 'append') {
|
|
192
|
+
const existing = fs.readFileSync(destPath, 'utf-8');
|
|
193
|
+
const separator = '\n\n---\n\n<!-- cc-starter section -->\n';
|
|
194
|
+
fs.writeFileSync(destPath, existing + separator + rendered, 'utf-8');
|
|
195
|
+
} else {
|
|
196
|
+
fs.writeFileSync(destPath, rendered, 'utf-8');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Copy scripts/stats/ files (always overwrite).
|
|
202
|
+
*/
|
|
203
|
+
function copyScriptsStats(cwd) {
|
|
204
|
+
const src = path.join(TEMPLATE_DIR, 'scripts', 'stats');
|
|
205
|
+
const dest = path.join(cwd, 'scripts', 'stats');
|
|
206
|
+
fs.ensureDirSync(dest);
|
|
207
|
+
|
|
208
|
+
const files = fs.readdirSync(src).filter(f => f.endsWith('.js'));
|
|
209
|
+
for (const file of files) {
|
|
210
|
+
fs.copySync(path.join(src, file), path.join(dest, file));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return { created: files.length };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Append cc-starter entries to .gitignore if not already present.
|
|
218
|
+
* @returns {boolean} true if .gitignore was modified
|
|
219
|
+
*/
|
|
220
|
+
function updateGitignore(cwd) {
|
|
221
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
222
|
+
let content = '';
|
|
223
|
+
|
|
224
|
+
if (fs.existsSync(gitignorePath)) {
|
|
225
|
+
content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const marker = '# cc-starter';
|
|
229
|
+
if (content.includes(marker)) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const block = [
|
|
234
|
+
'',
|
|
235
|
+
'# cc-starter',
|
|
236
|
+
'.vibe-stats.json',
|
|
237
|
+
'stats/report.html',
|
|
238
|
+
''
|
|
239
|
+
].join('\n');
|
|
240
|
+
|
|
241
|
+
// Ensure we start on a new line
|
|
242
|
+
const prefix = content.length > 0 && !content.endsWith('\n') ? '\n' : '';
|
|
243
|
+
fs.writeFileSync(gitignorePath, content + prefix + block, 'utf-8');
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Count files recursively in a directory.
|
|
249
|
+
*/
|
|
250
|
+
function countFiles(dir) {
|
|
251
|
+
if (!fs.existsSync(dir)) return 0;
|
|
252
|
+
let count = 0;
|
|
253
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
254
|
+
if (entry.isDirectory()) {
|
|
255
|
+
count += countFiles(path.join(dir, entry.name));
|
|
256
|
+
} else {
|
|
257
|
+
count += 1;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return count;
|
|
261
|
+
}
|
package/lib/wizard.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { basename, resolve } from 'path';
|
|
5
|
+
import {
|
|
6
|
+
PLUGIN_PRESETS,
|
|
7
|
+
ALL_PLUGINS,
|
|
8
|
+
REPORT_STYLES,
|
|
9
|
+
DEFAULT_HOURLY_RATE
|
|
10
|
+
} from './constants.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Detect project name from package.json or fall back to folder name.
|
|
14
|
+
*/
|
|
15
|
+
function detectProjectName() {
|
|
16
|
+
try {
|
|
17
|
+
const pkg = JSON.parse(readFileSync(resolve('package.json'), 'utf-8'));
|
|
18
|
+
if (pkg.name) return pkg.name;
|
|
19
|
+
} catch {
|
|
20
|
+
// no package.json — fall through
|
|
21
|
+
}
|
|
22
|
+
return basename(resolve('.'));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Interactive setup wizard.
|
|
27
|
+
* @param {string[]} techStack - Auto-detected technologies (e.g. ['Node.js', 'TypeScript', 'React'])
|
|
28
|
+
* @returns {Promise<{projectName: string, hourlyRate: number, reportStyle: string, plugins: object[], techStack: string[]}>}
|
|
29
|
+
*/
|
|
30
|
+
export async function wizard(techStack = []) {
|
|
31
|
+
console.log();
|
|
32
|
+
console.log(chalk.bold.cyan(' cc-starter') + chalk.dim(' — project kickstart wizard'));
|
|
33
|
+
console.log();
|
|
34
|
+
|
|
35
|
+
if (techStack.length > 0) {
|
|
36
|
+
console.log(chalk.dim(' Detected tech stack: ') + chalk.yellow(techStack.join(', ')));
|
|
37
|
+
console.log();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const defaultName = detectProjectName();
|
|
41
|
+
|
|
42
|
+
const answers = await inquirer.prompt([
|
|
43
|
+
{
|
|
44
|
+
type: 'input',
|
|
45
|
+
name: 'projectName',
|
|
46
|
+
message: 'Project name:',
|
|
47
|
+
default: defaultName
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: 'number',
|
|
51
|
+
name: 'hourlyRate',
|
|
52
|
+
message: 'Hourly rate for COCOMO estimation (\u20ac):',
|
|
53
|
+
default: DEFAULT_HOURLY_RATE
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: 'list',
|
|
57
|
+
name: 'reportStyle',
|
|
58
|
+
message: 'Report style:',
|
|
59
|
+
choices: Object.entries(REPORT_STYLES).map(([key, val]) => ({
|
|
60
|
+
name: val.label,
|
|
61
|
+
value: key
|
|
62
|
+
}))
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: 'list',
|
|
66
|
+
name: 'pluginPreset',
|
|
67
|
+
message: 'Plugin preset:',
|
|
68
|
+
choices: [
|
|
69
|
+
{ name: `Minimal — ${PLUGIN_PRESETS.minimal.length} plugin`, value: 'minimal' },
|
|
70
|
+
{ name: `Standard — ${PLUGIN_PRESETS.standard.length} plugins`, value: 'standard' },
|
|
71
|
+
{ name: `Full — ${PLUGIN_PRESETS.full.length} plugins`, value: 'full' },
|
|
72
|
+
{ name: 'Custom — pick individual plugins', value: 'custom' }
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: 'checkbox',
|
|
77
|
+
name: 'customPlugins',
|
|
78
|
+
message: 'Select plugins:',
|
|
79
|
+
when: (ans) => ans.pluginPreset === 'custom',
|
|
80
|
+
choices: ALL_PLUGINS.map((p) => ({
|
|
81
|
+
name: `${p.name} ${chalk.dim('— ' + p.desc)}`,
|
|
82
|
+
value: p,
|
|
83
|
+
checked: false
|
|
84
|
+
}))
|
|
85
|
+
}
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const plugins = answers.pluginPreset === 'custom'
|
|
89
|
+
? answers.customPlugins || []
|
|
90
|
+
: PLUGIN_PRESETS[answers.pluginPreset];
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
projectName: answers.projectName,
|
|
94
|
+
hourlyRate: answers.hourlyRate,
|
|
95
|
+
reportStyle: answers.reportStyle,
|
|
96
|
+
plugins,
|
|
97
|
+
techStack
|
|
98
|
+
};
|
|
99
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cc-starter",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Claude Code Project Kickstart — scaffolds an optimized dev environment with token-saving scripts, COCOMO estimation, and interactive plugin setup",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"cc-starter": "bin/cc-starter.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"claude-code",
|
|
11
|
+
"cli",
|
|
12
|
+
"scaffold",
|
|
13
|
+
"starter-kit",
|
|
14
|
+
"vibe-coding",
|
|
15
|
+
"token-savings",
|
|
16
|
+
"cocomo",
|
|
17
|
+
"developer-tools"
|
|
18
|
+
],
|
|
19
|
+
"author": "Lars Fanter",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"inquirer": "^9.2.0",
|
|
23
|
+
"chalk": "^5.3.0",
|
|
24
|
+
"fs-extra": "^11.2.0",
|
|
25
|
+
"handlebars": "^4.7.8"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18.0.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# CLAUDE.md - {{projectName}}
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
**Project:** {{projectName}}
|
|
5
|
+
{{#if techStack.languages.length}}
|
|
6
|
+
**Languages:** {{#each techStack.languages}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
|
|
7
|
+
{{/if}}
|
|
8
|
+
{{#if techStack.frameworks.length}}
|
|
9
|
+
**Frameworks:** {{#each techStack.frameworks}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
|
|
10
|
+
{{/if}}
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Quick Reference
|
|
15
|
+
|
|
16
|
+
### Token-Saving Scripts
|
|
17
|
+
```bash
|
|
18
|
+
node scripts/stats/vibe-code.js help # Code analysis (save ~90% tokens)
|
|
19
|
+
node scripts/stats/vibe-code.js types <f> # Extract types/interfaces
|
|
20
|
+
node scripts/stats/vibe-code.js tree [dir] # Clean directory tree
|
|
21
|
+
node scripts/stats/vibe-code.js imports <f> # Show imports
|
|
22
|
+
node scripts/stats/vibe-code.js funcs <f> # Function signatures
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Project Statistics
|
|
26
|
+
```bash
|
|
27
|
+
node scripts/stats/cocomo.js # Project cost estimation
|
|
28
|
+
node scripts/stats/project-report.js # HTML statistics report
|
|
29
|
+
node scripts/stats/vibe-stats.js report # Token savings report
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Rules
|
|
33
|
+
See `.claude/rules/` for working rules:
|
|
34
|
+
- `01-general.md` — Task tracking, planning, verification
|
|
35
|
+
- `02-code-standards.md` — Code quality, security, testing
|
|
36
|
+
- `03-dev-ops.md` — Git, environment, deployment
|
|
37
|
+
|
|
38
|
+
### Memory System
|
|
39
|
+
Persistent memory across sessions in `.claude/memory/`.
|
|
40
|
+
Index: `.claude/memory/MEMORY.md`
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
*Generated by [cc-starter](https://www.npmjs.com/package/cc-starter)*
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kickstart
|
|
3
|
+
description: Re-run cc-starter setup or upgrade existing configuration
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
To update your cc-starter configuration, run in your terminal:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx cc-starter
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
This will:
|
|
13
|
+
- Update rules to the latest version
|
|
14
|
+
- Add any missing scripts
|
|
15
|
+
- Install new plugins
|
|
16
|
+
- Regenerate CLAUDE.md if desired
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Project Memory
|
|
2
|
+
|
|
3
|
+
This is the memory index for this project. Claude Code uses this to persist knowledge across sessions.
|
|
4
|
+
|
|
5
|
+
## How It Works
|
|
6
|
+
- Each memory is stored as a separate .md file in this directory
|
|
7
|
+
- This file (MEMORY.md) is the index — keep it concise
|
|
8
|
+
- Memory types: user, feedback, project, reference
|
|
9
|
+
|
|
10
|
+
## Memories
|
|
11
|
+
<!-- Add memory entries below as they are created -->
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# General Working Rules
|
|
2
|
+
|
|
3
|
+
## 1. Task Tracking
|
|
4
|
+
For tasks with **3+ steps** ALWAYS:
|
|
5
|
+
- Use task tracking to manage work items
|
|
6
|
+
- Create each step as a task BEFORE starting
|
|
7
|
+
- Mark each task as completed immediately when done
|
|
8
|
+
|
|
9
|
+
## 2. Keep Documentation Modular
|
|
10
|
+
- Don't create sprawling status files
|
|
11
|
+
- Updates belong in the matching doc (feature docs, architecture docs)
|
|
12
|
+
- Keep a clean separation of concerns
|
|
13
|
+
|
|
14
|
+
## 3. Before Coding
|
|
15
|
+
- When unclear: Ask first, then implement
|
|
16
|
+
- When multiple approaches exist: Present options and wait for decision
|
|
17
|
+
|
|
18
|
+
## 4. When Things Go Wrong: STOP & Re-plan
|
|
19
|
+
- If an approach isn't working: **Stop immediately**, don't keep pushing
|
|
20
|
+
- Re-plan instead of repeating the same mistake
|
|
21
|
+
- Find root causes — no temporary workarounds or hacks
|
|
22
|
+
- Ask yourself: "Is this the elegant solution or a quick-fix?"
|
|
23
|
+
|
|
24
|
+
## 5. Verification: Diff Against Main Before "Done"
|
|
25
|
+
- Before claiming "done": run `git diff main` to check all changes are intentional
|
|
26
|
+
- Ask yourself: "Would a staff engineer approve this?"
|
|
27
|
+
- Build must be green
|
|
28
|
+
- No unintended changes in unrelated files
|
|
29
|
+
|
|
30
|
+
## 6. Design Documentation
|
|
31
|
+
When making design decisions, document the process:
|
|
32
|
+
- Summary of final decisions
|
|
33
|
+
- Questions asked with options and chosen answers
|
|
34
|
+
- Reasoning for each choice
|
|
35
|
+
- Technical details
|
|
36
|
+
- Open points
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Code Standards
|
|
2
|
+
|
|
3
|
+
## Security First
|
|
4
|
+
- Never commit secrets, API keys, or credentials
|
|
5
|
+
- Validate all external input
|
|
6
|
+
- Use parameterized queries for databases
|
|
7
|
+
- Follow OWASP Top 10 guidelines
|
|
8
|
+
|
|
9
|
+
## Code Quality
|
|
10
|
+
- Write self-documenting code with clear naming
|
|
11
|
+
- Keep functions focused (single responsibility)
|
|
12
|
+
- Prefer composition over inheritance
|
|
13
|
+
- Handle errors explicitly — no silent catches
|
|
14
|
+
|
|
15
|
+
## Testing
|
|
16
|
+
- Write tests for new features and bug fixes
|
|
17
|
+
- Test edge cases and error paths
|
|
18
|
+
- Don't mock what you don't own — use integration tests where possible
|
|
19
|
+
|
|
20
|
+
## Internationalization (if applicable)
|
|
21
|
+
- No hardcoded user-facing strings
|
|
22
|
+
- Use your project's i18n solution consistently
|
|
23
|
+
- Keep translation files in sync across locales
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# DevOps & Deployment Rules
|
|
2
|
+
|
|
3
|
+
## Git Discipline
|
|
4
|
+
- Separate concerns in commits (app code vs. infrastructure vs. docs)
|
|
5
|
+
- Write descriptive commit messages explaining WHY, not just WHAT
|
|
6
|
+
- Never force-push to main/master without team agreement
|
|
7
|
+
|
|
8
|
+
## Environment Variables
|
|
9
|
+
- New env vars must be documented
|
|
10
|
+
- Never commit .env files with real values
|
|
11
|
+
- Provide .env.example with placeholder values
|
|
12
|
+
|
|
13
|
+
## Port Management
|
|
14
|
+
- Stick to one dev server port — don't spawn multiple
|
|
15
|
+
- Kill orphan processes before starting new dev servers
|
|
16
|
+
|
|
17
|
+
## Build Verification
|
|
18
|
+
- Always run build/lint before committing
|
|
19
|
+
- Fix warnings, don't suppress them
|
|
20
|
+
- Keep CI/CD pipeline green
|