create-harness-vibe-coding 0.1.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/bin/create-harness-vibe-coding.js +2 -0
- package/package.json +39 -0
- package/src/generator.js +107 -0
- package/src/index.js +106 -0
- package/src/prompts.js +41 -0
- package/templates/common/.claude/rules/ecc/common.md +32 -0
- package/templates/common/.claude/settings.json +34 -0
- package/templates/common/AGENTS.md +5 -0
- package/templates/common/CLAUDE.md +119 -0
- package/templates/common/MEMORY.md +35 -0
- package/templates/common/SETUP.md +91 -0
- package/templates/common/docs/README.md +112 -0
- package/templates/common/docs/domain/ports.md +73 -0
- package/templates/common/docs/features/_template.md +135 -0
- package/templates/common/docs/harness/agent-workflow.md +145 -0
- package/templates/common/docs/harness/architecture.md +87 -0
- package/templates/common/docs/harness/data-flow.md +59 -0
- package/templates/common/docs/harness/state-machines.md +50 -0
- package/templates/common/docs/research/PRD.md +63 -0
- package/templates/common/docs/research/scaffolds.md +60 -0
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-harness-vibe-coding",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold a vibe-coding agentic harness — CLAUDE.md, docs/, .claude skeleton ready for ECC agents/skills/rules",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-harness-vibe-coding": "./bin/create-harness-vibe-coding.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"templates/"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"start": "node src/index.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@clack/prompts": "^0.7.0",
|
|
19
|
+
"picocolors": "^1.1.0"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/LiWeny16/q-profit.git",
|
|
27
|
+
"directory": "create-harness-vibe-coding"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"claude-code",
|
|
31
|
+
"harness",
|
|
32
|
+
"scaffold",
|
|
33
|
+
"vibe-coding",
|
|
34
|
+
"agentic",
|
|
35
|
+
"ecc",
|
|
36
|
+
"superpowers"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT"
|
|
39
|
+
}
|
package/src/generator.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const TEMPLATES_DIR = path.resolve(__dirname, '..', 'templates', 'common');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Copy a directory recursively, replacing {{vars}} in file contents.
|
|
11
|
+
* Skips dirs named '.gitkeep-placeholder'.
|
|
12
|
+
*/
|
|
13
|
+
function copyDir(src, dest, vars) {
|
|
14
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
15
|
+
|
|
16
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
17
|
+
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const srcPath = path.join(src, entry.name);
|
|
20
|
+
const destPath = path.join(dest, entry.name);
|
|
21
|
+
|
|
22
|
+
if (entry.isDirectory()) {
|
|
23
|
+
copyDir(srcPath, destPath, vars);
|
|
24
|
+
} else {
|
|
25
|
+
let content = fs.readFileSync(srcPath, 'utf-8');
|
|
26
|
+
|
|
27
|
+
// Replace template variables
|
|
28
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
29
|
+
content = content.replaceAll(`{{${key}}}`, value);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fs.writeFileSync(destPath, content, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Walk a directory and return relative paths of all files.
|
|
39
|
+
*/
|
|
40
|
+
function walkFiles(dir, base = dir) {
|
|
41
|
+
const results = [];
|
|
42
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
43
|
+
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
const full = path.join(dir, entry.name);
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
results.push(...walkFiles(full, base));
|
|
48
|
+
} else {
|
|
49
|
+
results.push(path.relative(base, full));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return results;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function generate({ projectName, targetDir }) {
|
|
57
|
+
const created = [];
|
|
58
|
+
const errors = [];
|
|
59
|
+
|
|
60
|
+
// Resolve targetDir relative to cwd
|
|
61
|
+
const resolvedDir = path.resolve(process.cwd(), targetDir);
|
|
62
|
+
|
|
63
|
+
// Check if target exists and is non-empty
|
|
64
|
+
if (fs.existsSync(resolvedDir)) {
|
|
65
|
+
const existing = fs.readdirSync(resolvedDir).filter(f => f !== '.git');
|
|
66
|
+
if (existing.length > 0) {
|
|
67
|
+
console.log(pc.yellow(`⚠ 目录 "${targetDir}" 已存在且非空,文件可能被覆盖`));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const vars = { projectName };
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// 1. Copy all template files
|
|
75
|
+
console.log(pc.cyan('📋 复制模板文件...'));
|
|
76
|
+
copyDir(TEMPLATES_DIR, resolvedDir, vars);
|
|
77
|
+
|
|
78
|
+
// List all created files from templates
|
|
79
|
+
created.push(...walkFiles(TEMPLATES_DIR).map(f => f.replace(/\\/g, '/')));
|
|
80
|
+
|
|
81
|
+
// 2. Create empty directories
|
|
82
|
+
console.log(pc.cyan('📁 创建占位目录...'));
|
|
83
|
+
const emptyDirs = [
|
|
84
|
+
'.claude/agents',
|
|
85
|
+
'.claude/skills',
|
|
86
|
+
'.claude/hooks',
|
|
87
|
+
'tests',
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
for (const dir of emptyDirs) {
|
|
91
|
+
const dirPath = path.join(resolvedDir, dir);
|
|
92
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
93
|
+
created.push(`${dir}/ (empty)`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 3. Create .gitkeep in tests/
|
|
97
|
+
const gitkeepPath = path.join(resolvedDir, 'tests', '.gitkeep');
|
|
98
|
+
fs.writeFileSync(gitkeepPath, '', 'utf-8');
|
|
99
|
+
created.push('tests/.gitkeep');
|
|
100
|
+
|
|
101
|
+
return { success: true, created, errors };
|
|
102
|
+
|
|
103
|
+
} catch (err) {
|
|
104
|
+
errors.push(err.message);
|
|
105
|
+
return { success: false, created, errors };
|
|
106
|
+
}
|
|
107
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as p from '@clack/prompts';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { askProjectName, askTargetDir } from './prompts.js';
|
|
5
|
+
import { generate } from './generator.js';
|
|
6
|
+
|
|
7
|
+
// Parse CLI args for non-interactive mode
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const argName = args[0];
|
|
10
|
+
const argDir = args[1];
|
|
11
|
+
|
|
12
|
+
console.log('');
|
|
13
|
+
console.log(pc.magenta('╔══════════════════════════════════════════╗'));
|
|
14
|
+
console.log(pc.magenta('║ 🎯 create-harness-vibe-coding ║'));
|
|
15
|
+
console.log(pc.magenta('║ Agentic Harness — Vibe Coding Ready ║'));
|
|
16
|
+
console.log(pc.magenta('╚══════════════════════════════════════════╝'));
|
|
17
|
+
console.log('');
|
|
18
|
+
|
|
19
|
+
let projectName, targetDir;
|
|
20
|
+
|
|
21
|
+
// Non-interactive mode: use CLI args or defaults
|
|
22
|
+
if (argName) {
|
|
23
|
+
projectName = argName;
|
|
24
|
+
targetDir = argDir || `./${projectName}`;
|
|
25
|
+
|
|
26
|
+
console.log(pc.dim('────────────────────────────────────────────'));
|
|
27
|
+
console.log(` 项目名称 ${pc.green(projectName)}`);
|
|
28
|
+
console.log(` 目标目录 ${pc.green(targetDir)}`);
|
|
29
|
+
console.log(` 将创建 ${pc.cyan('CLAUDE.md, docs/, .claude/, SETUP.md, tests/')}`);
|
|
30
|
+
console.log(pc.dim('────────────────────────────────────────────'));
|
|
31
|
+
console.log('');
|
|
32
|
+
|
|
33
|
+
const result = generate({ projectName, targetDir });
|
|
34
|
+
printResult(result, targetDir);
|
|
35
|
+
} else {
|
|
36
|
+
// Interactive mode
|
|
37
|
+
try {
|
|
38
|
+
projectName = await askProjectName();
|
|
39
|
+
} catch {
|
|
40
|
+
// Fallback for non-TTY
|
|
41
|
+
projectName = 'my-vibe-project';
|
|
42
|
+
console.log(pc.dim(` 项目名称: ${projectName} (默认)`));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
targetDir = await askTargetDir(projectName);
|
|
47
|
+
} catch {
|
|
48
|
+
targetDir = `./${projectName}`;
|
|
49
|
+
console.log(pc.dim(` 目标目录: ${targetDir} (默认)`));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log('');
|
|
53
|
+
console.log(pc.dim('────────────────────────────────────────────'));
|
|
54
|
+
console.log(` 项目名称 ${pc.green(projectName)}`);
|
|
55
|
+
console.log(` 目标目录 ${pc.green(targetDir)}`);
|
|
56
|
+
console.log(` 将创建 ${pc.cyan('CLAUDE.md, docs/, .claude/, SETUP.md, tests/')}`);
|
|
57
|
+
console.log(pc.dim('────────────────────────────────────────────'));
|
|
58
|
+
console.log('');
|
|
59
|
+
|
|
60
|
+
let proceed = true;
|
|
61
|
+
try {
|
|
62
|
+
proceed = await p.confirm({
|
|
63
|
+
message: '确认生成?',
|
|
64
|
+
initialValue: true,
|
|
65
|
+
});
|
|
66
|
+
if (p.isCancel(proceed)) proceed = false;
|
|
67
|
+
} catch {
|
|
68
|
+
proceed = true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!proceed) {
|
|
72
|
+
p.cancel('已取消');
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log('');
|
|
77
|
+
const result = generate({ projectName, targetDir });
|
|
78
|
+
printResult(result, targetDir);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function printResult(result, targetDir) {
|
|
82
|
+
if (result.success) {
|
|
83
|
+
console.log(pc.green(`\n✅ 项目已创建! 共 ${result.created.length} 个文件\n`));
|
|
84
|
+
|
|
85
|
+
console.log(pc.bold('下一步:'));
|
|
86
|
+
console.log(` ${pc.cyan(`cd ${targetDir}`)}`);
|
|
87
|
+
console.log(` ${pc.cyan('claude')} # 启动 Claude Code`);
|
|
88
|
+
console.log(` 告诉 Claude: "${pc.yellow('阅读 SETUP.md 并帮我初始化项目')}"`);
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(pc.dim(' SETUP.md 是临时文件,初始化完成后可删除'));
|
|
91
|
+
console.log('');
|
|
92
|
+
|
|
93
|
+
if (result.errors.length > 0) {
|
|
94
|
+
console.log(pc.red(`\n⚠ ${result.errors.length} 个警告:`));
|
|
95
|
+
for (const err of result.errors) {
|
|
96
|
+
console.log(pc.red(` - ${err}`));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
console.log(pc.red('\n❌ 生成失败:'));
|
|
101
|
+
for (const err of result.errors) {
|
|
102
|
+
console.log(pc.red(` - ${err}`));
|
|
103
|
+
}
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
package/src/prompts.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
|
|
4
|
+
export async function askProjectName() {
|
|
5
|
+
const name = await p.text({
|
|
6
|
+
message: '项目名称?',
|
|
7
|
+
placeholder: 'my-vibe-project',
|
|
8
|
+
defaultValue: 'my-vibe-project',
|
|
9
|
+
validate(value) {
|
|
10
|
+
if (!value.trim()) return '项目名不能为空';
|
|
11
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(value)) return '只允许字母、数字、连字符和下划线';
|
|
12
|
+
return;
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (p.isCancel(name)) {
|
|
17
|
+
p.cancel('已取消');
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return name.trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function askTargetDir(projectName) {
|
|
25
|
+
const dir = await p.text({
|
|
26
|
+
message: '目标目录?',
|
|
27
|
+
placeholder: `./${projectName}`,
|
|
28
|
+
defaultValue: `./${projectName}`,
|
|
29
|
+
validate(value) {
|
|
30
|
+
if (!value.trim()) return '目录不能为空';
|
|
31
|
+
return;
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (p.isCancel(dir)) {
|
|
36
|
+
p.cancel('已取消');
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return dir.trim();
|
|
41
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Universal coding principles — always applied"
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Universal Coding Rules
|
|
7
|
+
|
|
8
|
+
## Architecture Boundaries (CLAUDE.md enforced)
|
|
9
|
+
- `domain/` depends on stdlib only — no infrastructure imports ever
|
|
10
|
+
- `application/` depends on `domain/` only
|
|
11
|
+
- `infrastructure/` implements ports defined in `domain/`
|
|
12
|
+
- `harness/` coordinates workflows, contains no domain business rules
|
|
13
|
+
|
|
14
|
+
## Code Style
|
|
15
|
+
- Prefer small, deterministic, pure functions
|
|
16
|
+
- Functions > 30 lines need a comment explaining why they can't be split
|
|
17
|
+
- No hidden global state in strategy or service objects
|
|
18
|
+
- Explicit over implicit: type hints on all function signatures
|
|
19
|
+
|
|
20
|
+
## Git Workflow
|
|
21
|
+
- Commit format: `type(scope): message` — types: feat/fix/test/docs/refactor/chore
|
|
22
|
+
- Every feature PR must include: implementation + tests + doc update
|
|
23
|
+
- Keep commits atomic; one logical change per commit
|
|
24
|
+
|
|
25
|
+
## Testing
|
|
26
|
+
- Write tests before or alongside implementation, not after
|
|
27
|
+
- Test behavior, not implementation details
|
|
28
|
+
- Tests must be deterministic and not depend on wall-clock time
|
|
29
|
+
|
|
30
|
+
## Security
|
|
31
|
+
- No API keys or secrets in source code — use environment variables
|
|
32
|
+
- Validate all external data at system boundaries
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
|
3
|
+
"permissions": {
|
|
4
|
+
"allow": [
|
|
5
|
+
"Bash(git *)",
|
|
6
|
+
"Bash(npm *)",
|
|
7
|
+
"Bash(npx *)",
|
|
8
|
+
"Bash(python *)",
|
|
9
|
+
"Bash(pytest *)",
|
|
10
|
+
"Bash(pip *)",
|
|
11
|
+
"Bash(go *)",
|
|
12
|
+
"Bash(cargo *)",
|
|
13
|
+
"Bash(node *)",
|
|
14
|
+
"Read",
|
|
15
|
+
"Glob",
|
|
16
|
+
"Grep",
|
|
17
|
+
"WebFetch",
|
|
18
|
+
"WebSearch"
|
|
19
|
+
],
|
|
20
|
+
"deny": [
|
|
21
|
+
"Bash(rm -rf *)",
|
|
22
|
+
"Bash(sudo *)",
|
|
23
|
+
"Bash(curl *)",
|
|
24
|
+
"Bash(wget *)",
|
|
25
|
+
"Bash(> *)",
|
|
26
|
+
"Read(.env*)",
|
|
27
|
+
"Read(**/secrets/**)",
|
|
28
|
+
"Read(**/*.key)",
|
|
29
|
+
"Read(**/*.pem)"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"hooks": {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
@docs/README.md
|
|
4
|
+
|
|
5
|
+
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
|
6
|
+
|
|
7
|
+
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
|
8
|
+
|
|
9
|
+
## 1. Think Before Coding
|
|
10
|
+
|
|
11
|
+
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
|
12
|
+
|
|
13
|
+
Before implementing:
|
|
14
|
+
- State your assumptions explicitly. If uncertain, ask.
|
|
15
|
+
- If multiple interpretations exist, present them - don't pick silently.
|
|
16
|
+
- If a simpler approach exists, say so. Push back when warranted.
|
|
17
|
+
- If something is unclear, stop. Name what's confusing. Ask.
|
|
18
|
+
|
|
19
|
+
## 2. Simplicity First
|
|
20
|
+
|
|
21
|
+
**Minimum code that solves the problem. Nothing speculative.**
|
|
22
|
+
|
|
23
|
+
- No features beyond what was asked.
|
|
24
|
+
- No abstractions for single-use code.
|
|
25
|
+
- No "flexibility" or "configurability" that wasn't requested.
|
|
26
|
+
- No error handling for impossible scenarios.
|
|
27
|
+
- If you write 200 lines and it could be 50, rewrite it.
|
|
28
|
+
|
|
29
|
+
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
|
30
|
+
|
|
31
|
+
## 3. Surgical Changes
|
|
32
|
+
|
|
33
|
+
**Touch only what you must. Clean up only your own mess.**
|
|
34
|
+
|
|
35
|
+
When editing existing code:
|
|
36
|
+
- Don't "improve" adjacent code, comments, or formatting.
|
|
37
|
+
- Don't refactor things that aren't broken.
|
|
38
|
+
- Match existing style, even if you'd do it differently.
|
|
39
|
+
- If you notice unrelated dead code, mention it - don't delete it.
|
|
40
|
+
|
|
41
|
+
When your changes create orphans:
|
|
42
|
+
- Remove imports/variables/functions that YOUR changes made unused.
|
|
43
|
+
- Don't remove pre-existing dead code unless asked.
|
|
44
|
+
|
|
45
|
+
The test: Every changed line should trace directly to the user's request.
|
|
46
|
+
|
|
47
|
+
## 4. Goal-Driven Execution
|
|
48
|
+
|
|
49
|
+
**Define success criteria. Loop until verified.**
|
|
50
|
+
|
|
51
|
+
Transform tasks into verifiable goals:
|
|
52
|
+
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
|
53
|
+
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
|
54
|
+
- "Refactor X" → "Ensure tests pass before and after"
|
|
55
|
+
|
|
56
|
+
For multi-step tasks, state a brief plan:
|
|
57
|
+
```
|
|
58
|
+
1. [Step] → verify: [check]
|
|
59
|
+
2. [Step] → verify: [check]
|
|
60
|
+
3. [Step] → verify: [check]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 5. 记忆与自学习
|
|
72
|
+
|
|
73
|
+
遇到用户表达"记住 / 偏好 / 习惯 / 纠正"意图时,**持久化到 `MEMORY.md`**,让后续会话能复用。
|
|
74
|
+
|
|
75
|
+
### 5.1 触发词
|
|
76
|
+
|
|
77
|
+
当用户消息包含以下关键词或意图时,必须写入 `MEMORY.md`:
|
|
78
|
+
|
|
79
|
+
| 触发词/句式 | 含义 | 写入栏目 |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| "记住…"、"记下…"、"帮我记住…" | 用户想持久化一条事实/偏好 | User Mem |
|
|
82
|
+
| "以后不要…"、"下次别…"、"别再…" | 用户纠正某个行为,以后避免 | User Mem |
|
|
83
|
+
| "下次记得…"、"以后都…"、"以后遇到…就…" | 用户指定未来的默认行为 | User Mem |
|
|
84
|
+
| "我喜欢…"、"我习惯…"、"我偏好…" | 用户表达工作习惯或偏好 | User Mem |
|
|
85
|
+
|
|
86
|
+
如果消息是否触发记忆有歧义,先问用户确认再写入。不要为每次对话自动记录。
|
|
87
|
+
|
|
88
|
+
### 5.2 MEMORY.md 写入格式
|
|
89
|
+
|
|
90
|
+
在 `MEMORY.md` 的 `## User Mem` 栏目下,按日期倒序追加。每条格式:
|
|
91
|
+
|
|
92
|
+
```markdown
|
|
93
|
+
### YYYY-MM-DD — <简短标题>
|
|
94
|
+
- **触发词**:<用户原话>
|
|
95
|
+
- **行为**:<以后应该怎么做 / 避免做什么>
|
|
96
|
+
- **原因**:<用户说明的原因,如果有>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 5.3 自学习:工具调用规范
|
|
100
|
+
|
|
101
|
+
Claude Code 发现以下模式时,在不涉及用户隐私的前提下,自动追加到 `MEMORY.md` 的 `## 工具调用规范` 栏目:
|
|
102
|
+
|
|
103
|
+
| 发现模式 | 记录内容 |
|
|
104
|
+
|---|---|
|
|
105
|
+
| 某工具/MCP/skill 连续 3 次以上被高频调用但每次都失败或有更优替代 | 记录:场景 → 失败原因 → 推荐替代方案 |
|
|
106
|
+
| 某类代码错误反复出现在同一文件/模块(如 lint 报错、类型错误、导入错误) | 记录:错误类型 → 触发条件 → 修复模板 |
|
|
107
|
+
| 某个 skill/MCP 的调用方式与最佳实践不符导致低效 | 记录:正确用法 → 避免的用法 |
|
|
108
|
+
|
|
109
|
+
格式:
|
|
110
|
+
|
|
111
|
+
```markdown
|
|
112
|
+
### <工具名/skill名> — <问题简述>
|
|
113
|
+
- **场景**:<什么情况下触发>
|
|
114
|
+
- **问题**:<具体现象>
|
|
115
|
+
- **方案**:<推荐做法>
|
|
116
|
+
- **日期**:<首次记录日期>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
如果同一问题已存在记录,更新其内容而非新增一条。如果新发现与旧记录矛盾,替换旧记录并标注日期。
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# MEMORY.md — {{projectName}} 项目资源索引
|
|
2
|
+
|
|
3
|
+
> 当前项目事实源从 `CLAUDE.md -> docs/README.md` 进入。此文件用于跨会话持久化:资源索引、用户偏好、工具调用规范。
|
|
4
|
+
|
|
5
|
+
## Agents(子代理)
|
|
6
|
+
|
|
7
|
+
> 待 Claude Code 从 [ECC](https://github.com/affaan-m/ECC) 初始化。
|
|
8
|
+
> 初始化命令:在 Claude Code 中描述你的项目类型和语言,Claude 会自动拉取匹配的 agents。
|
|
9
|
+
|
|
10
|
+
## Skills(工作流)
|
|
11
|
+
|
|
12
|
+
> 待 Claude Code 从 [ECC](https://github.com/affaan-m/ECC) 或 [awesome-claude-code-config](https://github.com/Mizoreww/awesome-claude-code-config) 初始化。
|
|
13
|
+
|
|
14
|
+
## Rules(代码规则)
|
|
15
|
+
|
|
16
|
+
放在 `.claude/rules/ecc/` 下,由 CC 引擎自动加载:
|
|
17
|
+
|
|
18
|
+
- [common.md](.claude/rules/ecc/common.md) — 通用编码规则(alwaysApply: true)
|
|
19
|
+
- 语言专属规则待 Claude Code 初始化(如 python.md、typescript.md 等)
|
|
20
|
+
|
|
21
|
+
## Harness(运行时)
|
|
22
|
+
|
|
23
|
+
- [架构文档](docs/harness/architecture.md)
|
|
24
|
+
- [Agent 工作流](docs/harness/agent-workflow.md)
|
|
25
|
+
|
|
26
|
+
## User Mem
|
|
27
|
+
|
|
28
|
+
> 用户偏好、习惯、纠正指令。由 CLAUDE.md §5 触发写入,日期倒序。
|
|
29
|
+
> 当前无记录 — 等待用户首次"记住…"指令。
|
|
30
|
+
|
|
31
|
+
## 工具调用规范
|
|
32
|
+
|
|
33
|
+
> Claude Code 自学习记录:高频工具/MCP/skill 的坑、替代方案、常见错误修复模板。
|
|
34
|
+
> 由 CLAUDE.md §5.3 触发写入。
|
|
35
|
+
> 当前无记录 — 等待首次自动发现。
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# SETUP.md — 项目初始化指南
|
|
2
|
+
|
|
3
|
+
> ⚠️ **临时文件** — 本文件在初始化完成后应删除:`rm SETUP.md`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 你现在拥有了什么
|
|
8
|
+
|
|
9
|
+
`npx create-harness-vibe-coding` 为你搭建了一个 **vibe-coding agentic harness** 骨架:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
{{projectName}}/
|
|
13
|
+
CLAUDE.md ← Agent 行为规范 + 记忆自学习系统
|
|
14
|
+
AGENTS.md ← Coding agent 入口
|
|
15
|
+
MEMORY.md ← 跨会话资源索引
|
|
16
|
+
docs/ ← 架构文档(分层规则、工作流、端口合同)
|
|
17
|
+
.claude/
|
|
18
|
+
settings.json ← 权限 + Hooks 配置
|
|
19
|
+
agents/ ← 空 — 待拉取 ECC agents
|
|
20
|
+
skills/ ← 空 — 待拉取 ECC skills
|
|
21
|
+
hooks/ ← 空 — 待配置自动化钩子
|
|
22
|
+
rules/ecc/
|
|
23
|
+
common.md ← 通用编码规则(始终生效)
|
|
24
|
+
tests/ ← 待初始化
|
|
25
|
+
.gitignore ← 基础 Git 忽略规则
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 下一步:用 Claude Code 初始化项目内容
|
|
31
|
+
|
|
32
|
+
### Step 1 — 启动 Claude Code
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
claude
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Step 2 — 描述你的项目
|
|
39
|
+
|
|
40
|
+
告诉 Claude 你的项目类型、语言和技术栈。Claude 会:
|
|
41
|
+
|
|
42
|
+
1. 从 [ECC](https://github.com/affaan-m/ECC) 拉取匹配的 **agents**(如 code-reviewer、planner、security-reviewer)
|
|
43
|
+
2. 从 ECC 拉取匹配的 **skills**(如 tdd-workflow、django-patterns、react-patterns)
|
|
44
|
+
3. 从 ECC 拉取对应语言的 **rules**(如 python.md、typescript.md)
|
|
45
|
+
4. 根据项目需要配置 **hooks**(如 PostToolUse 自动 lint、PreToolUse 安全门禁)
|
|
46
|
+
|
|
47
|
+
**对话示例**:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
你: 这是一个 Python 量化交易项目,帮我从 ECC 初始化 agents、skills 和 rules
|
|
51
|
+
你: 这是一个 React + TypeScript 前端项目,需要 TDD workflow
|
|
52
|
+
你: 这是一个 Go 微服务项目,帮我配置对应的代码审查和测试 skills
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Step 3 — 可选:安装 Superpowers 强化工程纪律
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# 在 Claude Code 中运行
|
|
59
|
+
/plugin install superpowers@claude-plugins-official
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Superpowers 提供:brainstorming → writing-plans → TDD → code-review 的完整闭环。
|
|
63
|
+
|
|
64
|
+
### Step 4 — 初始化完成后
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
rm SETUP.md
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 参考资源
|
|
73
|
+
|
|
74
|
+
| 资源 | 地址 | 用途 |
|
|
75
|
+
|------|------|------|
|
|
76
|
+
| ECC | https://github.com/affaan-m/ECC | Agents / Skills / Rules 主仓库 |
|
|
77
|
+
| awesome-claude-code-config | https://github.com/Mizoreww/awesome-claude-code-config | 多语言规则 + 自学习配置 |
|
|
78
|
+
| Superpowers | https://github.com/obra/superpowers | 工程纪律插件 |
|
|
79
|
+
| claude-toolbox | https://github.com/serpro69/claude-toolbox | 多语言技能工具包 |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 自定义
|
|
84
|
+
|
|
85
|
+
- **CLAUDE.md** — 可按项目需求修改行为规范
|
|
86
|
+
- **.claude/settings.json** — 按需调整权限和 hooks
|
|
87
|
+
- **.claude/rules/ecc/** — 语言规则由 Claude Code 自动添加
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
> 本项目由 `create-harness-vibe-coding` 生成。保留 MIT 许可。
|