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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "k-harness",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "LLM Development Harness — IDE-agnostic rules, skills, and agents that prevent common AI coding failures",
5
5
  "keywords": [
6
6
  "llm",
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
- '---\napplyTo: "**/*.test.ts,**/*.test.js,**/*.spec.ts,**/*.spec.js,**/__mocks__/**,**/__tests__/**"\n---\n\n' +
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
- '---\napplyTo: "src/**/*.ts,src/**/*.js"\n---\n\n' +
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
- '---\ndescription: Testing rules — mock sync, forbidden patterns\nglobs: "**/*.test.*,**/*.spec.*,**/__mocks__/**,**/__tests__/**"\nalwaysApply: false\n---\n\n' +
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
- '---\ndescription: Backend code rules — architecture enforcement, type safety\nglobs: "src/**/*.ts,src/**/*.js"\nalwaysApply: false\n---\n\n' +
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
- '---\ndescription: Testing rules — mock sync, forbidden patterns\ntype: auto\nglobs: "**/*.test.*,**/*.spec.*,**/__mocks__/**,**/__tests__/**"\n---\n\n' +
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
- '---\ndescription: Backend code rules — architecture enforcement, type safety\ntype: auto\nglobs: "src/**/*.ts,src/**/*.js"\n---\n\n' +
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
- '---\ndescription: Testing rules — mock sync, forbidden patterns\ntype: auto\nglobs: "**/*.test.*,**/*.spec.*,**/__mocks__/**,**/__tests__/**"\n---\n\n' +
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
- '---\ndescription: Backend code rules — architecture enforcement, type safety\ntype: auto\nglobs: "src/**/*.ts,src/**/*.js"\n---\n\n' +
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
- console.log(`\n Installing for ${gen.name}...\n`);
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! Edit docs/project-state.md to set up your first sprint.\n`);
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 };