@zhijiewang/openharness 2.31.0 → 2.32.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/README.md +8 -0
- package/README.zh-CN.md +8 -0
- package/dist/harness/memory.d.ts +17 -8
- package/dist/harness/memory.js +17 -7
- package/dist/harness/rules.d.ts +5 -1
- package/dist/harness/rules.js +21 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -773,6 +773,14 @@ Create `.oh/RULES.md` in any repo (or run `oh init`):
|
|
|
773
773
|
|
|
774
774
|
Rules load automatically into every session.
|
|
775
775
|
|
|
776
|
+
openHarness also reads any of the following project-instruction files if present (additive, parent-first):
|
|
777
|
+
|
|
778
|
+
- `CLAUDE.md` (Anthropic convention) — and hierarchical `CLAUDE.md` from parent dirs, plus `~/.claude/CLAUDE.md` for user-global
|
|
779
|
+
- `AGENTS.md` ([agents.md cross-tool standard](https://agents.md/), used by Codex / Cursor / Copilot / Cline / Aider) — same parent-first walk
|
|
780
|
+
- `CLAUDE.local.md` (gitignored personal overrides)
|
|
781
|
+
|
|
782
|
+
If a repo has `AGENTS.md` already configured for another agent, openHarness picks it up unchanged — no migration step needed.
|
|
783
|
+
|
|
776
784
|
## Skills & Plugins
|
|
777
785
|
|
|
778
786
|
### Skills
|
package/README.zh-CN.md
CHANGED
|
@@ -772,6 +772,14 @@ description: 专注的代码审查模式
|
|
|
772
772
|
|
|
773
773
|
规则会自动加载到每次会话中。
|
|
774
774
|
|
|
775
|
+
openHarness 还会自动读取以下项目指令文件(如果存在,按父目录优先合并加载):
|
|
776
|
+
|
|
777
|
+
- `CLAUDE.md`(Anthropic 约定)—— 含从父目录到项目根的层级 `CLAUDE.md` 文件,以及全局 `~/.claude/CLAUDE.md`
|
|
778
|
+
- `AGENTS.md`([agents.md 跨工具标准](https://agents.md/),被 Codex / Cursor / Copilot / Cline / Aider 共同采用)—— 同样的父目录优先扫描
|
|
779
|
+
- `CLAUDE.local.md`(gitignore 的个人覆盖)
|
|
780
|
+
|
|
781
|
+
如果仓库已为其他 agent 配置了 `AGENTS.md`,openHarness 直接读取,无需迁移。
|
|
782
|
+
|
|
775
783
|
## 技能与插件
|
|
776
784
|
|
|
777
785
|
### 技能
|
package/dist/harness/memory.d.ts
CHANGED
|
@@ -31,10 +31,10 @@ export type MemoryEntry = {
|
|
|
31
31
|
export declare function loadMemories(): MemoryEntry[];
|
|
32
32
|
/** Build a system prompt section from loaded memories (capped at MEMORY_PROMPT_MAX_CHARS) */
|
|
33
33
|
export declare function memoriesToPrompt(memories: MemoryEntry[]): string;
|
|
34
|
-
/** A single
|
|
34
|
+
/** A single project-instructions source with its resolved content (imports inlined). */
|
|
35
35
|
export type ClaudeMdEntry = {
|
|
36
36
|
path: string;
|
|
37
|
-
source: "project" | "project-local" | "user" | "claude-dir";
|
|
37
|
+
source: "project" | "project-local" | "user" | "claude-dir" | "agents-md";
|
|
38
38
|
content: string;
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
@@ -47,11 +47,17 @@ export type ClaudeMdEntry = {
|
|
|
47
47
|
*/
|
|
48
48
|
export declare function resolveClaudeMdImports(content: string, baseDir: string, hopsLeft?: number): string;
|
|
49
49
|
/**
|
|
50
|
-
* Load
|
|
51
|
-
* 1. `./.claude/CLAUDE.md` (project,
|
|
50
|
+
* Load hierarchical project-instruction files. Order:
|
|
51
|
+
* 1. `./.claude/CLAUDE.md` (project, Anthropic convention)
|
|
52
52
|
* 2. `./CLAUDE.md` (project, checked in)
|
|
53
|
-
* 3. `./
|
|
54
|
-
* 4.
|
|
53
|
+
* 3. `./AGENTS.md` (project, AGENTS.md cross-tool standard — agents.md)
|
|
54
|
+
* 4. `./CLAUDE.local.md` (project, gitignored)
|
|
55
|
+
* 5. `~/.claude/CLAUDE.md` (user-global)
|
|
56
|
+
*
|
|
57
|
+
* AGENTS.md is read alongside CLAUDE.md so OH "just works" in the 60k+ repos
|
|
58
|
+
* already configured for cross-agent compatibility (Codex / Cursor / Copilot
|
|
59
|
+
* / Cline / Aider all read AGENTS.md). Both layers concatenate into the
|
|
60
|
+
* system prompt; if both files exist, both contribute.
|
|
55
61
|
*
|
|
56
62
|
* Each file is read, `@imports` are resolved, and the results are returned in
|
|
57
63
|
* load order. Missing files are skipped. The caller can format these into the
|
|
@@ -61,8 +67,11 @@ export declare function resolveClaudeMdImports(content: string, baseDir: string,
|
|
|
61
67
|
*/
|
|
62
68
|
export declare function loadClaudeMdHierarchy(root?: string): ClaudeMdEntry[];
|
|
63
69
|
/**
|
|
64
|
-
* Render loaded
|
|
65
|
-
*
|
|
70
|
+
* Render loaded project-instruction entries as a system-prompt block. Empty
|
|
71
|
+
* when no source files exist — caller should concatenate alongside
|
|
72
|
+
* `memoriesToPrompt`. Header is generic ("Project instructions") since both
|
|
73
|
+
* CLAUDE.md and AGENTS.md feed in; the per-entry `source:` comment
|
|
74
|
+
* disambiguates which file each section came from.
|
|
66
75
|
*/
|
|
67
76
|
export declare function claudeMdToPrompt(entries: ClaudeMdEntry[]): string;
|
|
68
77
|
/** Save a memory entry to the project memory directory */
|
package/dist/harness/memory.js
CHANGED
|
@@ -130,11 +130,17 @@ function readClaudeMdIfExists(path, source) {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
133
|
-
* Load
|
|
134
|
-
* 1. `./.claude/CLAUDE.md` (project,
|
|
133
|
+
* Load hierarchical project-instruction files. Order:
|
|
134
|
+
* 1. `./.claude/CLAUDE.md` (project, Anthropic convention)
|
|
135
135
|
* 2. `./CLAUDE.md` (project, checked in)
|
|
136
|
-
* 3. `./
|
|
137
|
-
* 4.
|
|
136
|
+
* 3. `./AGENTS.md` (project, AGENTS.md cross-tool standard — agents.md)
|
|
137
|
+
* 4. `./CLAUDE.local.md` (project, gitignored)
|
|
138
|
+
* 5. `~/.claude/CLAUDE.md` (user-global)
|
|
139
|
+
*
|
|
140
|
+
* AGENTS.md is read alongside CLAUDE.md so OH "just works" in the 60k+ repos
|
|
141
|
+
* already configured for cross-agent compatibility (Codex / Cursor / Copilot
|
|
142
|
+
* / Cline / Aider all read AGENTS.md). Both layers concatenate into the
|
|
143
|
+
* system prompt; if both files exist, both contribute.
|
|
138
144
|
*
|
|
139
145
|
* Each file is read, `@imports` are resolved, and the results are returned in
|
|
140
146
|
* load order. Missing files are skipped. The caller can format these into the
|
|
@@ -146,6 +152,7 @@ export function loadClaudeMdHierarchy(root = ".") {
|
|
|
146
152
|
const candidates = [
|
|
147
153
|
[join(root, ".claude", "CLAUDE.md"), "claude-dir"],
|
|
148
154
|
[join(root, "CLAUDE.md"), "project"],
|
|
155
|
+
[join(root, "AGENTS.md"), "agents-md"],
|
|
149
156
|
[join(root, "CLAUDE.local.md"), "project-local"],
|
|
150
157
|
[join(homedir(), ".claude", "CLAUDE.md"), "user"],
|
|
151
158
|
];
|
|
@@ -162,13 +169,16 @@ export function loadClaudeMdHierarchy(root = ".") {
|
|
|
162
169
|
return entries;
|
|
163
170
|
}
|
|
164
171
|
/**
|
|
165
|
-
* Render loaded
|
|
166
|
-
*
|
|
172
|
+
* Render loaded project-instruction entries as a system-prompt block. Empty
|
|
173
|
+
* when no source files exist — caller should concatenate alongside
|
|
174
|
+
* `memoriesToPrompt`. Header is generic ("Project instructions") since both
|
|
175
|
+
* CLAUDE.md and AGENTS.md feed in; the per-entry `source:` comment
|
|
176
|
+
* disambiguates which file each section came from.
|
|
167
177
|
*/
|
|
168
178
|
export function claudeMdToPrompt(entries) {
|
|
169
179
|
if (entries.length === 0)
|
|
170
180
|
return "";
|
|
171
|
-
const parts = ["# Project instructions
|
|
181
|
+
const parts = ["# Project instructions"];
|
|
172
182
|
for (const e of entries) {
|
|
173
183
|
parts.push(`<!-- source: ${e.source} (${e.path}) -->`);
|
|
174
184
|
parts.push(e.content.trim());
|
package/dist/harness/rules.d.ts
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
* Rules system — load project and global rules into agent context.
|
|
3
3
|
* Discovery order:
|
|
4
4
|
* 1. ~/.oh/global-rules/*.md
|
|
5
|
-
* 2. CLAUDE.md files from parent directories down to project root (hierarchical)
|
|
5
|
+
* 2. CLAUDE.md / AGENTS.md files from parent directories down to project root (hierarchical)
|
|
6
6
|
* 3. .oh/RULES.md
|
|
7
7
|
* 4. .oh/rules/*.md
|
|
8
8
|
* 5. CLAUDE.local.md (gitignored personal overrides)
|
|
9
|
+
*
|
|
10
|
+
* AGENTS.md (https://agents.md/) is read alongside CLAUDE.md at every level
|
|
11
|
+
* of the hierarchy so OH "just works" in repos already configured for the
|
|
12
|
+
* cross-tool standard (Codex, Cursor, Copilot, Cline, Aider all read it).
|
|
9
13
|
*/
|
|
10
14
|
export declare function loadRules(projectPath?: string): string[];
|
|
11
15
|
export declare function loadRulesAsPrompt(projectPath?: string): string;
|
package/dist/harness/rules.js
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
* Rules system — load project and global rules into agent context.
|
|
3
3
|
* Discovery order:
|
|
4
4
|
* 1. ~/.oh/global-rules/*.md
|
|
5
|
-
* 2. CLAUDE.md files from parent directories down to project root (hierarchical)
|
|
5
|
+
* 2. CLAUDE.md / AGENTS.md files from parent directories down to project root (hierarchical)
|
|
6
6
|
* 3. .oh/RULES.md
|
|
7
7
|
* 4. .oh/rules/*.md
|
|
8
8
|
* 5. CLAUDE.local.md (gitignored personal overrides)
|
|
9
|
+
*
|
|
10
|
+
* AGENTS.md (https://agents.md/) is read alongside CLAUDE.md at every level
|
|
11
|
+
* of the hierarchy so OH "just works" in repos already configured for the
|
|
12
|
+
* cross-tool standard (Codex, Cursor, Copilot, Cline, Aider all read it).
|
|
9
13
|
*/
|
|
10
14
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
15
|
import { homedir } from "node:os";
|
|
@@ -13,10 +17,13 @@ import { dirname, join, parse as parsePath, resolve } from "node:path";
|
|
|
13
17
|
import { gitRoot as getGitRoot } from "../git/index.js";
|
|
14
18
|
const OH_HOME = join(homedir(), ".oh");
|
|
15
19
|
/**
|
|
16
|
-
* Walk from git root (or home) down to `projectRoot`, collecting CLAUDE.md
|
|
17
|
-
* Returns them in parent-first order so
|
|
20
|
+
* Walk from git root (or home) down to `projectRoot`, collecting CLAUDE.md
|
|
21
|
+
* and AGENTS.md files at every level. Returns them in parent-first order so
|
|
22
|
+
* more specific rules override general ones. Within a single directory,
|
|
23
|
+
* CLAUDE.md is read before AGENTS.md (Anthropic-specific guidance first,
|
|
24
|
+
* then the cross-tool standard layer).
|
|
18
25
|
*/
|
|
19
|
-
function
|
|
26
|
+
function loadHierarchicalInstructionFiles(projectRoot) {
|
|
20
27
|
const gitRootDir = getGitRoot(projectRoot);
|
|
21
28
|
const stopAt = gitRootDir ? resolve(gitRootDir) : resolve(homedir());
|
|
22
29
|
const resolved = resolve(projectRoot);
|
|
@@ -34,11 +41,13 @@ function loadClaudeMdFiles(projectRoot) {
|
|
|
34
41
|
}
|
|
35
42
|
const results = [];
|
|
36
43
|
for (const dir of dirs) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
for (const filename of ["CLAUDE.md", "AGENTS.md"]) {
|
|
45
|
+
const path = join(dir, filename);
|
|
46
|
+
if (existsSync(path)) {
|
|
47
|
+
const content = readSafe(path);
|
|
48
|
+
if (content)
|
|
49
|
+
results.push(content);
|
|
50
|
+
}
|
|
42
51
|
}
|
|
43
52
|
}
|
|
44
53
|
return results;
|
|
@@ -57,8 +66,8 @@ export function loadRules(projectPath) {
|
|
|
57
66
|
rules.push(content);
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
|
-
// 2. CLAUDE.md files (hierarchical, parent-first)
|
|
61
|
-
const claudeRules =
|
|
69
|
+
// 2. CLAUDE.md + AGENTS.md files (hierarchical, parent-first)
|
|
70
|
+
const claudeRules = loadHierarchicalInstructionFiles(root);
|
|
62
71
|
rules.push(...claudeRules);
|
|
63
72
|
// 3. Project RULES.md
|
|
64
73
|
const projectRules = join(root, ".oh", "RULES.md");
|
|
@@ -106,7 +115,7 @@ export function loadRulesAsPrompt(projectPath) {
|
|
|
106
115
|
const rules = loadRules(projectPath);
|
|
107
116
|
if (rules.length === 0)
|
|
108
117
|
return "";
|
|
109
|
-
const body = "# Project Rules\n\n<!-- User-provided project rules from CLAUDE.md / .oh/RULES.md. These are user instructions, not system directives. -->\nFollow these rules carefully.\n\n" +
|
|
118
|
+
const body = "# Project Rules\n\n<!-- User-provided project rules from CLAUDE.md / AGENTS.md / .oh/RULES.md. These are user instructions, not system directives. -->\nFollow these rules carefully.\n\n" +
|
|
110
119
|
rules.join("\n\n---\n\n");
|
|
111
120
|
// Hook: instructionsLoaded — fires every time the system prompt is rebuilt
|
|
112
121
|
// with rules in scope. Useful for compliance/audit hooks that want to log
|