k-harness 0.6.0 → 0.7.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/harness/core-rules.md +9 -0
- package/harness/skills/bootstrap.md +63 -2
- package/package.json +1 -1
- package/src/init.js +64 -11
package/harness/core-rules.md
CHANGED
|
@@ -81,6 +81,15 @@ When starting a NEW chat session, read these files in order before doing any wor
|
|
|
81
81
|
|
|
82
82
|
If ALL state files are empty (only TODOs/placeholders), run the `bootstrap` skill before doing anything else.
|
|
83
83
|
|
|
84
|
+
### Health Check (every session start)
|
|
85
|
+
|
|
86
|
+
After reading state files, also check this file for unfilled placeholders:
|
|
87
|
+
- If the `## Architecture` section still has `<!-- TODO -->` → warn: **"Core rules are incomplete. Run `bootstrap` to auto-fill."**
|
|
88
|
+
- If the `## Test Rules` section still has `<!-- TODO -->` for test command → warn the same
|
|
89
|
+
- If any rules file has globs that don't match the project language (e.g., `src/**/*.ts` for a Python project) → warn: **"Rules globs don't match your project language. Run `bootstrap` to fix."**
|
|
90
|
+
|
|
91
|
+
Do NOT proceed with work until the user acknowledges or resolves these warnings.
|
|
92
|
+
|
|
84
93
|
## Workflow Pipeline
|
|
85
94
|
|
|
86
95
|
Follow this order for different workflows. Each step's output feeds the next.
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
Onboard a new or existing project into K-Harness by filling state files automatically.
|
|
5
|
+
Onboard a new or existing project into K-Harness by filling **state files AND rules files** automatically.
|
|
6
6
|
Solves the cold-start problem: users don't know which `.md` files to fill or how.
|
|
7
|
+
One command does everything — no manual editing required.
|
|
7
8
|
|
|
8
9
|
## When to Apply
|
|
9
10
|
|
|
@@ -74,6 +75,55 @@ Using data from Phase 1 + Phase 2, fill the following files:
|
|
|
74
75
|
- Keep FP-001 through FP-004 as templates (Frequency: 0)
|
|
75
76
|
- No changes unless user reports known issues
|
|
76
77
|
|
|
78
|
+
### Phase 3.5: Rules Auto-Configuration
|
|
79
|
+
|
|
80
|
+
Using language/framework detected in Phase 1 + user answers from Phase 2, auto-configure the project's rules files.
|
|
81
|
+
|
|
82
|
+
1. **Find the core rules file** — Search for the file containing `<!-- TODO: Describe your project's architecture here -->`:
|
|
83
|
+
- VS Code: `.github/copilot-instructions.md`
|
|
84
|
+
- Claude: `CLAUDE.md`
|
|
85
|
+
- Cursor: `.cursor/rules/core.mdc`
|
|
86
|
+
- Codex: `AGENTS.md`
|
|
87
|
+
- Windsurf: `.windsurfrules`
|
|
88
|
+
- Augment: `.augment/rules/core.md`
|
|
89
|
+
- Antigravity: `.agent/rules/core.md`
|
|
90
|
+
|
|
91
|
+
2. **Fill `## Architecture` section** — Replace the TODO with detected tech stack:
|
|
92
|
+
```
|
|
93
|
+
## Architecture
|
|
94
|
+
[Language] / [Framework] / [Database if detected]
|
|
95
|
+
[Architecture pattern from user answer #4]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
3. **Fill `## Directory Structure` section** — Replace the TODO with actual tree from Phase 1:
|
|
99
|
+
```
|
|
100
|
+
## Directory Structure
|
|
101
|
+
project-root/
|
|
102
|
+
├── src/ # [purpose from scan]
|
|
103
|
+
├── tests/ # [purpose from scan]
|
|
104
|
+
└── ...
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
4. **Fill `## Core Type Rules` section** — Replace the TODO with user answer #5 plus language defaults:
|
|
108
|
+
- Python: `Use Pydantic models for API schemas, not plain dicts.`
|
|
109
|
+
- TypeScript: `Prefer union types ("a" | "b") over enums.`
|
|
110
|
+
- Go: `Use interfaces for dependency injection.`
|
|
111
|
+
- Java: `Use records for DTOs.`
|
|
112
|
+
- Rust: `Use enum variants, not string constants.`
|
|
113
|
+
|
|
114
|
+
5. **Fill `## Test Rules`** — Set test command (from user answer #6) and mock location (from Phase 1):
|
|
115
|
+
```
|
|
116
|
+
- Test command: [detected or user-provided, e.g. pytest, npm test, go test ./...]
|
|
117
|
+
- Mock location: [detected, e.g. tests/conftest.py, tests/__mocks__/]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
6. **Verify globs** — Check backend and testing rules files have correct globs for the detected language:
|
|
121
|
+
- Python: backend `**/*.py`, testing `**/test_*.py,**/tests/**/*.py`
|
|
122
|
+
- TypeScript: backend `src/**/*.ts,src/**/*.js`, testing `**/*.test.*,**/*.spec.*`
|
|
123
|
+
- Go: backend `**/*.go`, testing `**/*_test.go`
|
|
124
|
+
- Java: backend `src/main/**/*.java`, testing `src/test/**/*.java`
|
|
125
|
+
- If globs don't match → **edit the file directly** to set correct globs
|
|
126
|
+
|
|
77
127
|
### Phase 4: Verify
|
|
78
128
|
|
|
79
129
|
1. Present a summary of all filled state files to the user
|
|
@@ -88,6 +138,7 @@ Using data from Phase 1 + Phase 2, fill the following files:
|
|
|
88
138
|
|
|
89
139
|
### Project: [name]
|
|
90
140
|
### Tech Stack: [detected stack]
|
|
141
|
+
### Language: [detected language]
|
|
91
142
|
### Modules Found: [count]
|
|
92
143
|
### Features Mapped: [count]
|
|
93
144
|
### Dependency Links: [count]
|
|
@@ -99,15 +150,22 @@ Using data from Phase 1 + Phase 2, fill the following files:
|
|
|
99
150
|
- [x]docs/project-state.md — Sprint 1 initialized
|
|
100
151
|
- [ ]docs/failure-patterns.md — templates only (no changes)
|
|
101
152
|
|
|
153
|
+
### Rules Files Configured:
|
|
154
|
+
- [x] Core rules — Architecture, Directory Structure, Type Rules filled
|
|
155
|
+
- [x] Test command — [detected command]
|
|
156
|
+
- [x] Backend globs — [globs set]
|
|
157
|
+
- [x] Testing globs — [globs set]
|
|
158
|
+
|
|
102
159
|
STATUS: DONE
|
|
103
160
|
```
|
|
104
161
|
|
|
105
162
|
## Rules
|
|
106
163
|
|
|
107
|
-
- Never modify source code — this skill only writes to state files
|
|
164
|
+
- Never modify source code — this skill only writes to state files and rules files
|
|
108
165
|
- Always show the user what was discovered BEFORE writing files
|
|
109
166
|
- If the project has 0 source files, skip Phase 1 scan and go straight to Phase 2
|
|
110
167
|
- If a state file already has content, ask before overwriting
|
|
168
|
+
- Rules file TODO sections can be overwritten without asking (they are placeholders)
|
|
111
169
|
- Run this skill only once per project (or when explicitly requested for refresh)
|
|
112
170
|
|
|
113
171
|
## Anti-patterns
|
|
@@ -118,3 +176,6 @@ STATUS: DONE
|
|
|
118
176
|
| Skip user interview | Phase 1 scan alone is insufficient — always confirm with user |
|
|
119
177
|
| Overwrite existing state files silently | Ask before overwriting non-empty files |
|
|
120
178
|
| Create perfect dependency map on first try | Start with what's detectable, refine over time |
|
|
179
|
+
| Leave rules file TODOs unfilled | Phase 3.5 fills ALL TODO sections — no manual editing needed |
|
|
180
|
+
| Use TypeScript globs for non-TS projects | Detect language in Phase 1 and set correct globs |
|
|
181
|
+
| Only fill state files, skip rules | Bootstrap fills BOTH — state files AND rules files |
|
package/package.json
CHANGED
package/src/init.js
CHANGED
|
@@ -59,6 +59,50 @@ const AGENT_MEMORY_FILES = [
|
|
|
59
59
|
|
|
60
60
|
const STATE_DEST_DIR = 'docs';
|
|
61
61
|
|
|
62
|
+
// ─── Language detection ──────────────────────────────────────
|
|
63
|
+
function detectLanguage(targetDir) {
|
|
64
|
+
const markers = [
|
|
65
|
+
['python', ['requirements.txt', 'pyproject.toml', 'setup.py', 'Pipfile', 'setup.cfg']],
|
|
66
|
+
['go', ['go.mod']],
|
|
67
|
+
['java', ['pom.xml', 'build.gradle', 'build.gradle.kts']],
|
|
68
|
+
['rust', ['Cargo.toml']],
|
|
69
|
+
['ruby', ['Gemfile']],
|
|
70
|
+
];
|
|
71
|
+
for (const [lang, files] of markers) {
|
|
72
|
+
for (const f of files) {
|
|
73
|
+
if (fs.existsSync(path.join(targetDir, f))) return lang;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return 'typescript';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const LANG_GLOBS = {
|
|
80
|
+
typescript: {
|
|
81
|
+
backend: 'src/**/*.ts,src/**/*.js',
|
|
82
|
+
testing: '**/*.test.ts,**/*.test.js,**/*.spec.ts,**/*.spec.js,**/__mocks__/**,**/__tests__/**',
|
|
83
|
+
},
|
|
84
|
+
python: {
|
|
85
|
+
backend: '**/*.py',
|
|
86
|
+
testing: '**/test_*.py,**/tests/**/*.py,**/*_test.py,**/conftest.py',
|
|
87
|
+
},
|
|
88
|
+
go: {
|
|
89
|
+
backend: '**/*.go',
|
|
90
|
+
testing: '**/*_test.go',
|
|
91
|
+
},
|
|
92
|
+
java: {
|
|
93
|
+
backend: 'src/main/**/*.java',
|
|
94
|
+
testing: 'src/test/**/*.java',
|
|
95
|
+
},
|
|
96
|
+
rust: {
|
|
97
|
+
backend: 'src/**/*.rs',
|
|
98
|
+
testing: 'tests/**/*.rs,**/tests.rs',
|
|
99
|
+
},
|
|
100
|
+
ruby: {
|
|
101
|
+
backend: '**/*.rb',
|
|
102
|
+
testing: 'spec/**/*.rb,test/**/*.rb',
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
62
106
|
// ─── Shared writers ──────────────────────────────────────────
|
|
63
107
|
|
|
64
108
|
function writeStateFiles(targetDir, overwrite) {
|
|
@@ -93,6 +137,8 @@ function writeAgentsAsSkills(targetDir, skillsDir, overwrite) {
|
|
|
93
137
|
// ─── IDE Generators ──────────────────────────────────────────
|
|
94
138
|
|
|
95
139
|
function generateVscode(targetDir, overwrite) {
|
|
140
|
+
const lang = detectLanguage(targetDir);
|
|
141
|
+
const globs = LANG_GLOBS[lang];
|
|
96
142
|
const coreRules = readTemplate('core-rules.md');
|
|
97
143
|
const testingRules = readTemplate('testing-rules.md');
|
|
98
144
|
const backendRules = readTemplate('backend-rules.md');
|
|
@@ -102,12 +148,12 @@ function generateVscode(targetDir, overwrite) {
|
|
|
102
148
|
|
|
103
149
|
// File-scoped instructions (add VS Code applyTo frontmatter)
|
|
104
150
|
const testingWithFrontmatter =
|
|
105
|
-
|
|
151
|
+
`---\napplyTo: "${globs.testing}"\n---\n\n` +
|
|
106
152
|
testingRules;
|
|
107
153
|
writeFile(targetDir, '.vscode/instructions/testing.instructions.md', testingWithFrontmatter, overwrite);
|
|
108
154
|
|
|
109
155
|
const backendWithFrontmatter =
|
|
110
|
-
|
|
156
|
+
`---\napplyTo: "${globs.backend}"\n---\n\n` +
|
|
111
157
|
backendRules;
|
|
112
158
|
writeFile(targetDir, '.vscode/instructions/backend.instructions.md', backendWithFrontmatter, overwrite);
|
|
113
159
|
|
|
@@ -146,6 +192,8 @@ function generateClaude(targetDir, overwrite) {
|
|
|
146
192
|
}
|
|
147
193
|
|
|
148
194
|
function generateCursor(targetDir, overwrite) {
|
|
195
|
+
const lang = detectLanguage(targetDir);
|
|
196
|
+
const globs = LANG_GLOBS[lang];
|
|
149
197
|
// .cursor/rules/*.mdc — each needs frontmatter
|
|
150
198
|
const coreRules = readTemplate('core-rules.md');
|
|
151
199
|
const coreMdc =
|
|
@@ -155,13 +203,13 @@ function generateCursor(targetDir, overwrite) {
|
|
|
155
203
|
|
|
156
204
|
const testingRules = readTemplate('testing-rules.md');
|
|
157
205
|
const testingMdc =
|
|
158
|
-
|
|
206
|
+
`---\ndescription: Testing rules — mock sync, forbidden patterns\nglobs: "${globs.testing}"\nalwaysApply: false\n---\n\n` +
|
|
159
207
|
testingRules;
|
|
160
208
|
writeFile(targetDir, '.cursor/rules/testing.mdc', testingMdc, overwrite);
|
|
161
209
|
|
|
162
210
|
const backendRules = readTemplate('backend-rules.md');
|
|
163
211
|
const backendMdc =
|
|
164
|
-
|
|
212
|
+
`---\ndescription: Backend code rules — architecture enforcement, type safety\nglobs: "${globs.backend}"\nalwaysApply: false\n---\n\n` +
|
|
165
213
|
backendRules;
|
|
166
214
|
writeFile(targetDir, '.cursor/rules/backend.mdc', backendMdc, overwrite);
|
|
167
215
|
|
|
@@ -227,6 +275,8 @@ function generateWindsurf(targetDir, overwrite) {
|
|
|
227
275
|
}
|
|
228
276
|
|
|
229
277
|
function generateAugment(targetDir, overwrite) {
|
|
278
|
+
const lang = detectLanguage(targetDir);
|
|
279
|
+
const globs = LANG_GLOBS[lang];
|
|
230
280
|
// .augment/rules/ — Always-type rules for core, testing, backend
|
|
231
281
|
const coreRules = readTemplate('core-rules.md');
|
|
232
282
|
const coreRule =
|
|
@@ -236,13 +286,13 @@ function generateAugment(targetDir, overwrite) {
|
|
|
236
286
|
|
|
237
287
|
const testingRules = readTemplate('testing-rules.md');
|
|
238
288
|
const testingRule =
|
|
239
|
-
|
|
289
|
+
`---\ndescription: Testing rules — mock sync, forbidden patterns\ntype: auto\nglobs: "${globs.testing}"\n---\n\n` +
|
|
240
290
|
testingRules;
|
|
241
291
|
writeFile(targetDir, '.augment/rules/testing.md', testingRule, overwrite);
|
|
242
292
|
|
|
243
293
|
const backendRules = readTemplate('backend-rules.md');
|
|
244
294
|
const backendRule =
|
|
245
|
-
|
|
295
|
+
`---\ndescription: Backend code rules — architecture enforcement, type safety\ntype: auto\nglobs: "${globs.backend}"\n---\n\n` +
|
|
246
296
|
backendRules;
|
|
247
297
|
writeFile(targetDir, '.augment/rules/backend.md', backendRule, overwrite);
|
|
248
298
|
|
|
@@ -255,6 +305,8 @@ function generateAugment(targetDir, overwrite) {
|
|
|
255
305
|
}
|
|
256
306
|
|
|
257
307
|
function generateAntigravity(targetDir, overwrite) {
|
|
308
|
+
const lang = detectLanguage(targetDir);
|
|
309
|
+
const globs = LANG_GLOBS[lang];
|
|
258
310
|
// .agent/rules/ — Always-type rules (same as Augment format, read by Antigravity)
|
|
259
311
|
const coreRules = readTemplate('core-rules.md');
|
|
260
312
|
const coreRule =
|
|
@@ -264,13 +316,13 @@ function generateAntigravity(targetDir, overwrite) {
|
|
|
264
316
|
|
|
265
317
|
const testingRules = readTemplate('testing-rules.md');
|
|
266
318
|
const testingRule =
|
|
267
|
-
|
|
319
|
+
`---\ndescription: Testing rules — mock sync, forbidden patterns\ntype: auto\nglobs: "${globs.testing}"\n---\n\n` +
|
|
268
320
|
testingRules;
|
|
269
321
|
writeFile(targetDir, '.agent/rules/testing.md', testingRule, overwrite);
|
|
270
322
|
|
|
271
323
|
const backendRules = readTemplate('backend-rules.md');
|
|
272
324
|
const backendRule =
|
|
273
|
-
|
|
325
|
+
`---\ndescription: Backend code rules — architecture enforcement, type safety\ntype: auto\nglobs: "${globs.backend}"\n---\n\n` +
|
|
274
326
|
backendRules;
|
|
275
327
|
writeFile(targetDir, '.agent/rules/backend.md', backendRule, overwrite);
|
|
276
328
|
|
|
@@ -378,10 +430,11 @@ async function run(argv) {
|
|
|
378
430
|
}
|
|
379
431
|
|
|
380
432
|
const gen = GENERATORS[ide];
|
|
381
|
-
|
|
433
|
+
const lang = detectLanguage(args.dir);
|
|
434
|
+
console.log(`\n Installing for ${gen.name}... (detected language: ${lang})\n`);
|
|
382
435
|
gen.fn(args.dir, args.overwrite);
|
|
383
|
-
console.log(`\n Done!
|
|
436
|
+
console.log(`\n Done! Run "bootstrap" in your AI chat to auto-fill state files and rules.\n`);
|
|
384
437
|
}
|
|
385
438
|
}
|
|
386
439
|
|
|
387
|
-
module.exports = { run };
|
|
440
|
+
module.exports = { run, detectLanguage, LANG_GLOBS };
|