openhermes 2.8.0 → 4.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.
Files changed (158) hide show
  1. package/CONTEXT.md +18 -0
  2. package/ETHOS.md +15 -0
  3. package/README.md +135 -292
  4. package/bootstrap.mjs +174 -512
  5. package/harness/agents/openhermes.md +87 -0
  6. package/harness/codex/CONSTITUTION.md +70 -148
  7. package/harness/codex/ROUTING.md +126 -0
  8. package/harness/commands/oh-doctor.md +26 -0
  9. package/harness/instructions/CONVENTIONS.md +206 -206
  10. package/harness/instructions/RUNTIME.md +54 -31
  11. package/harness/skills/oh-builder/SKILL.md +98 -0
  12. package/harness/skills/oh-caveman/SKILL.md +33 -0
  13. package/harness/skills/oh-expert/SKILL.md +121 -0
  14. package/harness/skills/oh-freeze/SKILL.md +28 -0
  15. package/harness/skills/oh-gauntlet/SKILL.md +119 -0
  16. package/harness/skills/oh-grill/SKILL.md +77 -0
  17. package/harness/skills/oh-guard/SKILL.md +33 -0
  18. package/harness/skills/oh-handoff/SKILL.md +33 -0
  19. package/harness/skills/oh-health/SKILL.md +90 -0
  20. package/harness/skills/oh-init/SKILL.md +78 -0
  21. package/harness/skills/oh-investigate/SKILL.md +35 -0
  22. package/harness/skills/oh-issue/SKILL.md +36 -0
  23. package/harness/skills/oh-learn/SKILL.md +28 -0
  24. package/harness/skills/oh-manifest/SKILL.md +84 -0
  25. package/harness/skills/oh-plan-review/SKILL.md +128 -0
  26. package/harness/skills/oh-planner/SKILL.md +157 -0
  27. package/harness/skills/oh-prd/SKILL.md +35 -0
  28. package/harness/skills/oh-retro/SKILL.md +33 -0
  29. package/harness/skills/oh-review/SKILL.md +110 -0
  30. package/harness/skills/oh-security/SKILL.md +110 -0
  31. package/harness/skills/oh-ship/SKILL.md +39 -0
  32. package/harness/skills/oh-skill-craft/SKILL.md +107 -0
  33. package/harness/skills/oh-skills-link/SKILL.md +29 -0
  34. package/harness/skills/oh-skills-list/SKILL.md +31 -0
  35. package/harness/skills/oh-triage/SKILL.md +36 -0
  36. package/index.mjs +3 -60
  37. package/lib/harness-resolver.mjs +77 -0
  38. package/lib/logger.mjs +62 -0
  39. package/package.json +49 -53
  40. package/test/plugins-behavioral.test.mjs +64 -0
  41. package/test/plugins.test.mjs +62 -0
  42. package/autorecall.mjs +0 -237
  43. package/curator.mjs +0 -482
  44. package/harness/commands/build-fix.md +0 -60
  45. package/harness/commands/checkpoint.md +0 -68
  46. package/harness/commands/code-review.md +0 -71
  47. package/harness/commands/doctor.md +0 -42
  48. package/harness/commands/eval.md +0 -89
  49. package/harness/commands/go-build.md +0 -87
  50. package/harness/commands/go-review.md +0 -71
  51. package/harness/commands/harness-audit.md +0 -90
  52. package/harness/commands/learn.md +0 -37
  53. package/harness/commands/loop-start.md +0 -38
  54. package/harness/commands/loop-status.md +0 -30
  55. package/harness/commands/memory-search.md +0 -37
  56. package/harness/commands/model-route.md +0 -32
  57. package/harness/commands/ohc.md +0 -13
  58. package/harness/commands/orchestrate.md +0 -88
  59. package/harness/commands/plan.md +0 -53
  60. package/harness/commands/quality-gate.md +0 -35
  61. package/harness/commands/refactor-clean.md +0 -102
  62. package/harness/commands/rust-build.md +0 -78
  63. package/harness/commands/rust-review.md +0 -65
  64. package/harness/commands/security.md +0 -93
  65. package/harness/commands/setup-pm.md +0 -65
  66. package/harness/commands/skill-create.md +0 -99
  67. package/harness/commands/test-coverage.md +0 -80
  68. package/harness/commands/update-codemaps.md +0 -81
  69. package/harness/commands/update-docs.md +0 -67
  70. package/harness/commands/verify.md +0 -68
  71. package/harness/prompts/architect.txt +0 -189
  72. package/harness/prompts/build-cpp.md +0 -98
  73. package/harness/prompts/build-error-resolver.md +0 -44
  74. package/harness/prompts/build-go.md +0 -340
  75. package/harness/prompts/build-java.md +0 -140
  76. package/harness/prompts/build-kotlin.md +0 -137
  77. package/harness/prompts/build-rust.md +0 -108
  78. package/harness/prompts/code-reviewer.md +0 -40
  79. package/harness/prompts/doc-updater.md +0 -206
  80. package/harness/prompts/docs-lookup.md +0 -71
  81. package/harness/prompts/e2e-runner.txt +0 -317
  82. package/harness/prompts/explore.md +0 -42
  83. package/harness/prompts/harness-optimizer.md +0 -42
  84. package/harness/prompts/loop-operator.md +0 -53
  85. package/harness/prompts/planner.md +0 -37
  86. package/harness/prompts/refactor-cleaner.md +0 -256
  87. package/harness/prompts/review-cpp.md +0 -81
  88. package/harness/prompts/review-database.md +0 -261
  89. package/harness/prompts/review-go.md +0 -257
  90. package/harness/prompts/review-java.md +0 -113
  91. package/harness/prompts/review-kotlin.md +0 -143
  92. package/harness/prompts/review-python.md +0 -101
  93. package/harness/prompts/review-rust.md +0 -77
  94. package/harness/prompts/security-reviewer.md +0 -42
  95. package/harness/prompts/tdd-guide.md +0 -228
  96. package/harness/rules/audit.md +0 -84
  97. package/harness/rules/checkpointing.md +0 -75
  98. package/harness/rules/context-loading.md +0 -33
  99. package/harness/rules/credential-exposure.md +0 -0
  100. package/harness/rules/delegation.md +0 -80
  101. package/harness/rules/handoff.md +0 -267
  102. package/harness/rules/memory-management.md +0 -28
  103. package/harness/rules/precedence.md +0 -52
  104. package/harness/rules/promotion.md +0 -46
  105. package/harness/rules/ranking.md +0 -64
  106. package/harness/rules/retrieval.md +0 -94
  107. package/harness/rules/runtime-guards.md +0 -196
  108. package/harness/rules/self-heal.md +0 -79
  109. package/harness/rules/session-start.md +0 -34
  110. package/harness/rules/skills-management.md +0 -165
  111. package/harness/rules/state-drift.md +0 -192
  112. package/harness/rules/verification.md +0 -88
  113. package/harness/scripts/sync-commands.mjs +0 -259
  114. package/harness/skills/.bundled_manifest +0 -17
  115. package/harness/skills/.usage.json +0 -6
  116. package/harness/skills/api-design/SKILL.md +0 -523
  117. package/harness/skills/backend-patterns/SKILL.md +0 -598
  118. package/harness/skills/coding-standards/SKILL.md +0 -549
  119. package/harness/skills/e2e-testing/SKILL.md +0 -326
  120. package/harness/skills/frontend-patterns/SKILL.md +0 -642
  121. package/harness/skills/frontend-slides/SKILL.md +0 -184
  122. package/harness/skills/security-review/SKILL.md +0 -495
  123. package/harness/skills/strategic-compact/SKILL.md +0 -131
  124. package/harness/skills/tdd-workflow/SKILL.md +0 -463
  125. package/harness/skills/verification-loop/SKILL.md +0 -126
  126. package/lib/ambient-memory.mjs +0 -167
  127. package/lib/handoff.mjs +0 -171
  128. package/lib/hardening.mjs +0 -146
  129. package/lib/memory-tools-plugin.mjs +0 -368
  130. package/lib/ohc/block-sync.mjs +0 -69
  131. package/lib/ohc/compress/search.mjs +0 -152
  132. package/lib/ohc/compress/state.mjs +0 -76
  133. package/lib/ohc/config.mjs +0 -185
  134. package/lib/ohc/message-ids.mjs +0 -178
  135. package/lib/ohc/notify.mjs +0 -135
  136. package/lib/ohc/protected-patterns.mjs +0 -55
  137. package/lib/ohc/prune-apply.mjs +0 -134
  138. package/lib/ohc/pruner.mjs +0 -608
  139. package/lib/ohc/reaper.mjs +0 -70
  140. package/lib/ohc/state.mjs +0 -265
  141. package/lib/ohc/strategies/deduplication.mjs +0 -72
  142. package/lib/ohc/strategies/index.mjs +0 -2
  143. package/lib/ohc/strategies/purge-errors.mjs +0 -43
  144. package/lib/ohc/token-utils.mjs +0 -26
  145. package/lib/ohc/updater.mjs +0 -132
  146. package/lib/paths.mjs +0 -49
  147. package/lib/schema-validator.mjs +0 -79
  148. package/lib/search.mjs +0 -48
  149. package/schemas/audit.schema.json +0 -82
  150. package/schemas/backlog.schema.json +0 -63
  151. package/schemas/checkpoint.schema.json +0 -65
  152. package/schemas/constraint.schema.json +0 -62
  153. package/schemas/decision.schema.json +0 -63
  154. package/schemas/instinct.schema.json +0 -63
  155. package/schemas/loop-state.schema.json +0 -33
  156. package/schemas/mistake.schema.json +0 -64
  157. package/schemas/verification_receipt.schema.json +0 -88
  158. package/skill-builder.mjs +0 -88
package/bootstrap.mjs CHANGED
@@ -1,512 +1,174 @@
1
- import path from "node:path"
2
- import fs from "node:fs"
3
- import os from "node:os"
4
- import { fileURLToPath } from "node:url"
5
-
6
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
7
- const CONFIG_DIR = path.join(os.homedir(), ".config", "opencode")
8
- const OVERRIDE_SOUL = path.join(CONFIG_DIR, "SOUL.md")
9
- const REQUIRED_HARNESS_FILES = [
10
- ["codex", "CONSTITUTION.md"],
11
- ["instructions", "RUNTIME.md"],
12
- ["commands", "doctor.md"],
13
- ["prompts", "architect.txt"],
14
- ["rules", "precedence.md"],
15
- ["skills", "coding-standards", "SKILL.md"],
16
- ]
17
-
18
- function ancestorDirs(start, limit = 6) {
19
- const dirs = []
20
- let current = path.resolve(start)
21
- for (let i = 0; i < limit; i++) {
22
- dirs.push(current)
23
- const parent = path.dirname(current)
24
- if (parent === current) break
25
- current = parent
26
- }
27
- return dirs
28
- }
29
-
30
- function buildHarnessCandidates(currentDir, execPath, cwd) {
31
- const roots = [path.resolve(currentDir, "harness")]
32
- const seen = new Set(roots)
33
-
34
- const anchors = [path.dirname(execPath), path.dirname(path.dirname(execPath)), cwd]
35
- for (const anchor of anchors) {
36
- for (const dir of ancestorDirs(anchor)) {
37
- for (const root of [
38
- path.join(dir, "harness"),
39
- path.join(dir, "node_modules", "openhermes", "harness"),
40
- path.join(dir, "bin", "node_modules", "openhermes", "harness"),
41
- ]) {
42
- const normalized = path.normalize(root)
43
- if (seen.has(normalized)) continue
44
- seen.add(normalized)
45
- roots.push(normalized)
46
- }
47
- }
48
- }
49
-
50
- return roots
51
- }
52
-
53
- function hasRequiredHarnessFiles(root) {
54
- return REQUIRED_HARNESS_FILES.every(parts => fs.existsSync(path.join(root, ...parts)))
55
- }
56
-
57
- export function resolveHarnessRoot({
58
- currentDir = __dirname,
59
- execPath = process.execPath,
60
- cwd = process.cwd(),
61
- candidateRoots,
62
- } = {}) {
63
- const roots = candidateRoots ?? buildHarnessCandidates(currentDir, execPath, cwd)
64
- for (const root of roots) {
65
- if (hasRequiredHarnessFiles(root)) return root
66
- }
67
- return path.resolve(currentDir, "harness")
68
- }
69
-
70
- let _harnessDir
71
- export function setHarnessRootForTest(dir) { _harnessDir = dir }
72
- export function getHarnessDir() {
73
- if (!_harnessDir) _harnessDir = resolveHarnessRoot()
74
- return _harnessDir
75
- }
76
- function getRulesDir() { return path.join(getHarnessDir(), "rules") }
77
- function getSkillsDir() { return path.join(getHarnessDir(), "skills") }
78
- function getConstitutionFile() { return path.join(getHarnessDir(), "codex", "CONSTITUTION.md") }
79
- function getRuntimeFile() { return path.join(getHarnessDir(), "instructions", "RUNTIME.md") }
80
-
81
-
82
- function scanDirNames(dir) {
83
- try { return fs.readdirSync(dir).filter(f => f.endsWith(".md")).map(f => f.replace(/\.md$/, "")).sort() }
84
- catch { return [] }
85
- }
86
-
87
- function scanPromptNames(dir) {
88
- try { return fs.readdirSync(dir).filter(f => f.endsWith('.md') || f.endsWith('.txt')).map(f => path.basename(f, path.extname(f))).sort() }
89
- catch { return [] }
90
- }
91
-
92
- function scanSkillDirs(dir) {
93
- try { return fs.readdirSync(dir).filter(f => fs.statSync(path.join(dir, f)).isDirectory()).sort() }
94
- catch { return [] }
95
- }
96
-
97
- function scanSchemaNames(dir) {
98
- try { return fs.readdirSync(dir).filter(f => f.endsWith(".schema.json")).map(f => f.replace(/\.schema\.json$/, "")).filter(f => f !== "loop-state").sort() }
99
- catch { return [] }
100
- }
101
-
102
- export function buildCapabilityMap(hDir) {
103
- const cmds = scanDirNames(path.join(hDir, "commands"))
104
- if (!cmds.includes("update-me")) cmds.push("update-me")
105
- cmds.sort()
106
-
107
- const agents = scanPromptNames(path.join(hDir, "prompts"))
108
- const skills = scanSkillDirs(path.join(hDir, "skills"))
109
- const schemas = scanSchemaNames(path.join(__dirname, "schemas"))
110
-
111
- return [
112
- "## Capability Map",
113
- "",
114
- `Commands (${cmds.length}): /${cmds.join(" /")}`,
115
- `Subagents (${agents.length}): ${agents.join(" ")}`,
116
- `Skills (${skills.length}): ${skills.join(" ")}`,
117
- `Memory (${schemas.length}): ${schemas.join(" ")}`,
118
- "",
119
- `For problem specialist routing see Delegation below. Skills via \`skill\` tool. Memory via \`ohc_save\` etc.`,
120
- ].join("\n")
121
- }
122
-
123
- export function loadLocalSoulOverride(overridePath) {
124
- const filePath = overridePath || OVERRIDE_SOUL
125
- try {
126
- if (fs.existsSync(filePath)) {
127
- const text = fs.readFileSync(filePath, "utf8").trim()
128
- if (text) return text
129
- }
130
- } catch {}
131
- return null
132
- }
133
-
134
- function buildBootstrapContent() {
135
- let constitution = fs.readFileSync(getConstitutionFile(), "utf8")
136
- const localOverride = loadLocalSoulOverride()
137
- if (localOverride) {
138
- constitution += `\n\n## Local Overrides (survives reinstalls)\n\n${localOverride}`
139
- }
140
- const runtime = fs.readFileSync(getRuntimeFile(), "utf8")
141
- const capMap = buildCapabilityMap(getHarnessDir())
142
-
143
- const router = `## AGENTS.md
144
-
145
- OpenHermes thin constitutional router. Full harness → \`openhermes/harness/\`.
146
-
147
- ## Constitution
148
-
149
- Pragmatic. Concise. Task-oriented. Subagent-first. Inspect, then act. Scope to the problem. Verify, don't claim. Receipts over vibes. Recover by narrowing, not posturing. Skeptical — demand proof. Precision-first search: needle then broad, never reverse.
150
-
151
- ## Safety
152
-
153
- Snapshot before mutation. Never delete unrelated files. Never assume \`%USERPROFILE%\\.config\\opencode\` is a git repo. Verify or roll back. **NEVER delete \`auth.json\`** (\`%USERPROFILE%\\.local\\share\\opencode\\auth.json\`).
154
-
155
- ${capMap}
156
-
157
- ## Delegation (Mandatory)
158
-
159
- Main context = coordination + verification only. Substantive work → subagent.
160
-
161
- | Trigger | Subagent |
162
- |---------|----------|
163
- | Multi-file implementation | \`architect\` or \`planner\` |
164
- | Build/TS error | \`build-error-resolver\` |
165
- | Code review | \`code-reviewer\` |
166
- | Security audit | \`security-reviewer\` |
167
- | E2E testing | \`e2e-runner\` |
168
- | Multi-file search/exploration | \`explore\` or \`general\` |
169
- | Documentation lookup | \`docs-lookup\` |
170
- | Doc/codemap update | \`doc-updater\` |
171
- | Dead code cleanup | \`refactor-cleaner\` |
172
- | TDD workflow | \`tdd-guide\` |
173
- | Autonomous loop | \`loop-operator\` |
174
- | Go review | \`review-go\` |
175
- | Go build fix | \`build-go\` |
176
- | Database review | \`review-database\` |
177
- | C++ review | \`review-cpp\` |
178
- | Java review | \`review-java\` |
179
- | Java build fix | \`build-java\` |
180
- | Kotlin review | \`review-kotlin\` |
181
- | Kotlin build fix | \`build-kotlin\` |
182
- | Python review | \`review-python\` |
183
- | Rust review | \`review-rust\` |
184
- | Rust build fix | \`build-rust\` |
185
- | Any non-trivial multi-step | appropriate specialist |
186
-
187
- Never delegate trivial single-step ops. Subagent returns diff + summary + verification; inspect return only. Full ref: \`openhermes/harness/rules/delegation.md\`.
188
-
189
- ## Handoff Protocol
190
-
191
- Every agent knows its role, permissions, and when to delegate. Before delegating, assess task complexity (easy → direct, medium → single subagent, hard → sequential multi-agent, very-large → fan-out). Use structured handoff format documented in \`openhermes/harness/rules/handoff.md\`.
192
-
193
- - **Act**: Task matches your role and permissions → do it directly
194
- - **Delegate**: Task outside your role → pass to correct agent via \`task\` tool
195
- - **Escalate**: Review/planning agents must NEVER edit code. Delegate to builders.
196
- - **Learn**: After each task, check for repeated patterns. Persist to memory via \`ohc_save\`.
197
- - **Checkpoint**: Before every handoff, save a checkpoint.
198
-
199
- ## Memory — Gated & Precision-First
200
-
201
- - **Start**: Read recall cache first. If stale/missing → \`ohc_latest\` for relevant classes.
202
- - **Before work**: Narrow \`ohc_search\` by class, scope, keywords. Never read full indexes.
203
- - **Before close**: Query same-type mistakes (7 days). Match → \`code-reviewer\` or \`security-reviewer\`.
204
- - **On failure**: \`ohc_search\` for similar incidents. Search memory before asking user.
205
- - **Precision ladder**: \`ohc_latest\` → \`ohc_search\` → \`ohc_get\` → \`ohc_list\` (last resort). Full index reads only for explicit audit/repair tasks.
206
- - **Anti-spam**: No obvious facts, no one-off prefs, no temp state, no low-risk mistakes. Supersede, don't duplicate. Full rules: \`openhermes/harness/rules/retrieval.md\`, \`openhermes/harness/rules/memory-management.md\`.
207
-
208
- ## Self-Edit Authority
209
-
210
- | Auto | Conditional | Needs approval |
211
- |------|-------------|----------------|
212
- | Memory entries, mistakes, checkpoints, receipts | openhermes docs/schemas/templates/non-core rules patches | AGENTS.md core, model routing, permissions, config, protected settings |
213
-
214
- Full tiers: \`openhermes/harness/rules/self-heal.md\`.
215
-
216
- ## Precedence
217
-
218
- 1. User instruction. 2. Safety/legal/destructive guard. 3. Constitution (\`openhermes/harness/codex/\`). 4. Project constraints. 5. Project decisions. 6. Verified guards. 7. Checkpoints. 8. Instincts. 9. Freeform notes. Full: \`openhermes/harness/rules/precedence.md\`.
219
-
220
- ## Hygiene
221
-
222
- - Checkpoint on meaningful boundaries. Compress closed segments immediately.
223
- - After subagent return: verify → compress that block.
224
- - Compress proactively.
225
- - Skill candidates → \`/learn\` only if repeated pattern + \`ohc_search\` confirms no dup. See \`openhermes/harness/rules/skills-management.md\`.
226
- - Audit triggers: openhermes/config change, repeated failures, session start when last audit >7 days. See \`openhermes/harness/rules/audit.md\`.
227
-
228
- ## Escalation
229
-
230
- T0: observe → log mistake → smallest fix. T1: add prevention rule → verify. T2: diagnosis/specialist → backlog. T3: constrained safe mode. Full: \`openhermes/harness/rules/self-heal.md\`.
231
-
232
- ## State
233
-
234
- - **Config root**: \`%USERPROFILE%\\.config\\opencode\`
235
- - **Auth**: \`%USERPROFILE%\\.local\\share\\opencode\\auth.json\` (NEVER delete)
236
- - **Forensic ledger**: \`%USERPROFILE%\\.local\\share\\opencode\\opencode.db\``
237
-
238
- return [
239
- `<OPENHERMES_BOOTSTRAP>\nOpenHermes v${getOwnVersion()} active. Harness: \`openhermes/harness/\`. Memory at \`~/.local/share/opencode/openhermes/memory/\`. Rules at \`openhermes/harness/rules/\`. Skills discoverable via \`skill\` tool — use \`skill\` tool to list/load them.`,
240
- `<OPENHERMES_CONSTITUTION>\n${constitution}\n</OPENHERMES_CONSTITUTION>`,
241
- `<OPENHERMES_RUNTIME>\n${runtime}\n</OPENHERMES_RUNTIME>`,
242
- `<OPENHERMES_ROUTER>\n${router}\n</OPENHERMES_ROUTER>`
243
- ].join("\n\n")
244
- }
245
-
246
- const OWN_VERSION = (() => {
247
- try {
248
- return JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8")).version || "1.0.0"
249
- } catch { return "1.0.0" }
250
- })()
251
- function getOwnVersion() { return OWN_VERSION }
252
-
253
- export const BootstrapPlugin = async ({ client, directory }) => {
254
- let _bootstrapCache
255
-
256
- const getContent = () => {
257
- if (_bootstrapCache !== undefined) return _bootstrapCache
258
- try {
259
- _bootstrapCache = buildBootstrapContent()
260
- } catch (err) {
261
- console.error("[openhermes-bootstrap] failed to build bootstrap content:", err.message)
262
- _bootstrapCache = null
263
- }
264
- return _bootstrapCache
265
- }
266
-
267
- return {
268
- config: async (config) => {
269
- config.skills = config.skills || {}
270
- config.skills.paths = config.skills.paths || []
271
- if (!config.skills.paths.includes(getSkillsDir())) {
272
- config.skills.paths.push(getSkillsDir())
273
- }
274
-
275
- const PROMPTS_DIR = path.join(getHarnessDir(), "prompts")
276
- const COMMANDS_DIR = path.join(getHarnessDir(), "commands")
277
- const ct = (file) => {
278
- const fp = path.join(COMMANDS_DIR, file)
279
- try { return fs.readFileSync(fp, "utf8").trimEnd() + "\n\n$ARGUMENTS" }
280
- catch { return "$ARGUMENTS" }
281
- }
282
- const p = (name) => {
283
- const fp = path.join(PROMPTS_DIR, name)
284
- try { return fs.readFileSync(fp, "utf8").trimEnd() }
285
- catch { return "" }
286
- }
287
-
288
- const existingCommands = config.command ?? {}
289
- const existingAgents = { ...(config.agent ?? {}) }
290
-
291
- config.command = {
292
- ...existingCommands,
293
- "build-fix": { agent: "build-error-resolver", description: "Fix build and TypeScript errors", subtask: true, template: ct("build-fix.md") },
294
- "code-review": { agent: "code-reviewer", description: "Review code for quality, security, and maintainability", subtask: true, template: ct("code-review.md") },
295
- "plan": { agent: "planner", description: "Create a detailed implementation plan", subtask: true, template: ct("plan.md") },
296
- "security": { agent: "security-reviewer", description: "Run comprehensive security review", subtask: true, template: ct("security.md") },
297
- "doctor": { agent: "OpenHermes", description: "Run OpenCode OpenHermes health diagnostics", subtask: true, template: ct("doctor.md") },
298
- "memory-search": { agent: "OpenHermes", description: "Search OpenHermes memory with LLM summarization", subtask: true, template: ct("memory-search.md") },
299
- "learn": { agent: "OpenHermes", description: "Create a new skill from recent work patterns", subtask: true, template: ct("learn.md") },
300
- "ohc": { template: "", description: "OHC context management: /ohc status, /ohc compress [focus]" },
301
- "update-me": { template: "", description: "Force reinstall OpenHermes plugin from latest source" },
302
- "orchestrate": { agent: "planner", description: "Orchestrate multiple agents for complex tasks", subtask: true, template: ct("orchestrate.md") },
303
- "eval": { agent: "planner", description: "Evaluate implementation against acceptance criteria", subtask: true, template: ct("eval.md") },
304
- "model-route": { agent: "OpenHermes", description: "Recommend model tier by task complexity and budget", subtask: true, template: ct("model-route.md") },
305
- "quality-gate": { agent: "OpenHermes", description: "Run quality pipeline (format, lint, type check)", subtask: true, template: ct("quality-gate.md") },
306
- "test-coverage": { agent: "tdd-guide", description: "Analyze coverage reports and identify gaps", subtask: true, template: ct("test-coverage.md") },
307
- "update-docs": { agent: "doc-updater", description: "Update documentation for recent code changes", subtask: true, template: ct("update-docs.md") },
308
- "update-codemaps": { agent: "doc-updater", description: "Generate/update architecture codemaps", subtask: true, template: ct("update-codemaps.md") },
309
- "refactor-clean": { agent: "refactor-cleaner", description: "Remove dead code and consolidate duplicates", subtask: true, template: ct("refactor-clean.md") },
310
- "verify": { agent: "OpenHermes", description: "Run comprehensive verification loop (typecheck, lint, test, build)", subtask: true, template: ct("verify.md") },
311
- "checkpoint": { agent: "OpenHermes", description: "Save verification state and progress checkpoint", subtask: true, template: ct("checkpoint.md") },
312
- "loop-start": { agent: "loop-operator", description: "Start managed autonomous loop with safety defaults", subtask: true, template: ct("loop-start.md") },
313
- "loop-status": { agent: "OpenHermes", description: "Inspect active loop state, progress, and failure signals", subtask: true, template: ct("loop-status.md") },
314
- "harness-audit": { agent: "harness-optimizer", description: "Run harness self-audit across 7 categories", subtask: true, template: ct("harness-audit.md") },
315
- "setup-pm": { agent: "OpenHermes", description: "Configure package manager preference for the project", subtask: true, template: ct("setup-pm.md") },
316
- "go-build": { agent: "build-go", description: "Fix Go build, vet, and compilation errors", subtask: true, template: ct("go-build.md") },
317
- "go-review": { agent: "review-go", description: "Review Go code for idiomatic patterns and best practices", subtask: true, template: ct("go-review.md") },
318
- "rust-build": { agent: "build-rust", description: "Fix Rust build, clippy, and dependency errors", subtask: true, template: ct("rust-build.md") },
319
- "rust-review": { agent: "review-rust", description: "Review Rust code for safety, ownership, and idioms", subtask: true, template: ct("rust-review.md") },
320
- "skill-create": { agent: "OpenHermes", description: "Generate a new skill from git history analysis", subtask: true, template: ct("skill-create.md") },
321
- }
322
-
323
- config.experimental ??= {}
324
- config.experimental.primary_tools ??= []
325
- if (!config.experimental.primary_tools.includes("compress")) {
326
- config.experimental.primary_tools.push("compress")
327
- }
328
-
329
- config.agent = {
330
- ...existingAgents,
331
- "OpenHermes": {
332
- description: "Fully autonomous primary coding agent (all tools allowed)",
333
- mode: "primary",
334
- color: "#F59E0B",
335
- permission: {
336
- bash: { "*": "allow" },
337
- edit: "allow",
338
- read: "allow",
339
- task: { "*": "allow" },
340
- },
341
- },
342
- "architect": {
343
- description: "Software architecture specialist for system design",
344
- mode: "subagent",
345
- prompt: p("architect.txt"),
346
- permission: { read: "allow", edit: "deny", bash: "deny" },
347
- },
348
- "build-error-resolver": {
349
- description: "Build and TypeScript error resolution specialist",
350
- mode: "subagent",
351
- prompt: p("build-error-resolver.md"),
352
- permission: { read: "allow", edit: "allow" },
353
- },
354
- "code-reviewer": {
355
- description: "Expert code review specialist",
356
- mode: "subagent",
357
- prompt: p("code-reviewer.md"),
358
- permission: { read: "allow", edit: "deny", bash: "deny", task: { explore: "allow", "*": "deny" } },
359
- },
360
- "e2e-runner": {
361
- description: "End-to-end testing specialist using Playwright",
362
- mode: "subagent",
363
- prompt: p("e2e-runner.txt"),
364
- permission: { read: "allow", edit: "allow" },
365
- },
366
- "explore": {
367
- description: "Fast read-only codebase exploration agent",
368
- mode: "subagent",
369
- prompt: p("explore.md"),
370
- permission: { read: "allow", grep: "allow", glob: "allow", list: "allow", edit: "deny", bash: "deny" },
371
- },
372
- "planner": {
373
- description: "Expert planning specialist for complex features and refactoring",
374
- mode: "subagent",
375
- color: "#3B82F6",
376
- prompt: p("planner.md"),
377
- permission: { read: "allow", edit: "deny", bash: "deny" },
378
- },
379
- "security-reviewer": {
380
- description: "Security vulnerability detection and remediation specialist",
381
- mode: "subagent",
382
- prompt: p("security-reviewer.md"),
383
- permission: { read: "allow", edit: "deny", bash: "deny", task: { "*": "allow" } },
384
- },
385
- "docs-lookup": {
386
- description: "Documentation lookup via MCP — query any library docs in real-time",
387
- mode: "subagent",
388
- prompt: p("docs-lookup.md"),
389
- permission: { read: "allow", bash: "allow", edit: "deny" },
390
- },
391
- "doc-updater": {
392
- description: "Documentation and codemap generation/update specialist",
393
- mode: "subagent",
394
- prompt: p("doc-updater.md"),
395
- permission: { read: "allow", edit: "allow", bash: "allow" },
396
- },
397
- "refactor-cleaner": {
398
- description: "Dead code detection and safe removal specialist",
399
- mode: "subagent",
400
- prompt: p("refactor-cleaner.md"),
401
- permission: { read: "allow", edit: "allow" },
402
- },
403
- "loop-operator": {
404
- description: "Autonomous agent loop operator — safe iteration with stop conditions",
405
- mode: "subagent",
406
- prompt: p("loop-operator.md"),
407
- permission: { read: "allow", edit: "allow", bash: "allow", task: { "*": "allow" } },
408
- },
409
- "harness-optimizer": {
410
- description: "OpenHermes harness configuration optimizer — audit, tune, measure",
411
- mode: "subagent",
412
- prompt: p("harness-optimizer.md"),
413
- permission: { read: "allow", bash: "allow", edit: "deny" },
414
- },
415
- "tdd-guide": {
416
- description: "Test-Driven Development coach — red-green-refactor cycle enforcement",
417
- mode: "subagent",
418
- prompt: p("tdd-guide.md"),
419
- permission: { read: "allow", edit: "allow", bash: "allow" },
420
- },
421
- "review-go": {
422
- description: "Go code review specialist — idiomatic Go, concurrency, error handling",
423
- mode: "subagent",
424
- prompt: p("review-go.md"),
425
- permission: { read: "allow", bash: "allow", edit: "deny" },
426
- },
427
- "build-go": {
428
- description: "Go build error resolution specialist — go build, vet, staticcheck fixes",
429
- mode: "subagent",
430
- prompt: p("build-go.md"),
431
- permission: { read: "allow", edit: "allow", bash: "allow" },
432
- },
433
- "review-database": {
434
- description: "PostgreSQL database specialist — query optimization, schema, RLS, indexes",
435
- mode: "subagent",
436
- prompt: p("review-database.md"),
437
- permission: { read: "allow", bash: "allow", edit: "deny" },
438
- },
439
- "review-cpp": {
440
- description: "C++ code review specialist — memory safety, modern C++, RAII",
441
- mode: "subagent",
442
- prompt: p("review-cpp.md"),
443
- permission: { read: "allow", bash: "allow", edit: "deny" },
444
- },
445
- "build-cpp": {
446
- description: "C++ build error resolution specialist — CMake, linker, template errors",
447
- mode: "subagent",
448
- prompt: p("build-cpp.md"),
449
- permission: { read: "allow", edit: "allow", bash: "allow" },
450
- },
451
- "review-java": {
452
- description: "Java/Spring Boot review specialist — JPA, architecture, security",
453
- mode: "subagent",
454
- prompt: p("review-java.md"),
455
- permission: { read: "allow", bash: "allow", edit: "deny" },
456
- },
457
- "build-java": {
458
- description: "Java/Maven/Gradle build error resolution specialist",
459
- mode: "subagent",
460
- prompt: p("build-java.md"),
461
- permission: { read: "allow", edit: "allow", bash: "allow" },
462
- },
463
- "review-kotlin": {
464
- description: "Kotlin/Android review specialist — coroutines, Compose, architecture",
465
- mode: "subagent",
466
- prompt: p("review-kotlin.md"),
467
- permission: { read: "allow", bash: "allow", edit: "deny" },
468
- },
469
- "build-kotlin": {
470
- description: "Kotlin/Gradle build error resolution specialist",
471
- mode: "subagent",
472
- prompt: p("build-kotlin.md"),
473
- permission: { read: "allow", edit: "allow", bash: "allow" },
474
- },
475
- "review-python": {
476
- description: "Python code review specialist — PEP 8, type hints, security",
477
- mode: "subagent",
478
- prompt: p("review-python.md"),
479
- permission: { read: "allow", bash: "allow", edit: "deny" },
480
- },
481
- "review-rust": {
482
- description: "Rust code review specialist — ownership, lifetimes, safety",
483
- mode: "subagent",
484
- prompt: p("review-rust.md"),
485
- permission: { read: "allow", bash: "allow", edit: "deny" },
486
- },
487
- "build-rust": {
488
- description: "Rust build error resolution specialist — cargo, borrow checker, clippy",
489
- mode: "subagent",
490
- prompt: p("build-rust.md"),
491
- permission: { read: "allow", edit: "allow", bash: "allow" },
492
- },
493
- }
494
-
495
- config.default_agent = "OpenHermes"
496
- },
497
-
498
- "experimental.chat.messages.transform": async (_input, output) => {
499
- try {
500
- const bootstrap = getContent()
501
- if (!bootstrap || !output.messages || !output.messages.length) return
502
- const firstUser = output.messages.find(m => m && m.info && m.info.role === "user")
503
- if (!firstUser || !firstUser.parts || !firstUser.parts.length) return
504
- if (firstUser.parts.some(p => p.type === "text" && p.text.includes("OPENHERMES_BOOTSTRAP"))) return
505
- const ref = firstUser.parts[0]
506
- firstUser.parts.unshift({ ...ref, type: "text", text: bootstrap })
507
- } catch (err) {
508
- console.error("[openhermes-bootstrap] transform error:", err.message)
509
- }
510
- }
511
- }
512
- }
1
+ import path from "node:path"
2
+ import fs from "node:fs"
3
+ import { fileURLToPath } from "node:url"
4
+ import { createLogger } from "./lib/logger.mjs"
5
+ import { getHarnessDir, setHarnessRootForTest, resolveHarnessRoot } from "./lib/harness-resolver.mjs"
6
+
7
+ const log = createLogger("bootstrap")
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
9
+ const BOOTSTRAP_MARKER = "OPENHERMES_BOOTSTRAP"
10
+ const OPENHERMES_AGENT = "OpenHermes"
11
+
12
+ export { resolveHarnessRoot, setHarnessRootForTest, getHarnessDir }
13
+
14
+ function parseFrontmatter(raw) {
15
+ const frontmatter = {}
16
+ if (!raw) return frontmatter
17
+ for (const line of raw.split(/\r?\n/)) {
18
+ const idx = line.indexOf(":")
19
+ if (idx < 0) continue
20
+ const key = line.slice(0, idx).trim()
21
+ const value = line.slice(idx + 1).trim().replace(/^['"]|['"]$/g, "")
22
+ if (key) frontmatter[key] = value
23
+ }
24
+ return frontmatter
25
+ }
26
+
27
+ function readMarkdownDocument(filePath) {
28
+ if (!fs.existsSync(filePath)) return null
29
+ const source = fs.readFileSync(filePath, "utf8")
30
+ const match = source.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/)
31
+ const frontmatter = parseFrontmatter(match?.[1] ?? "")
32
+ const body = (match ? match[2] : source).trim()
33
+ return { frontmatter, body }
34
+ }
35
+
36
+ function readMarkdownDirectory(dir) {
37
+ if (!fs.existsSync(dir)) return []
38
+ return fs.readdirSync(dir)
39
+ .filter(name => name.endsWith(".md") && name.toLowerCase() !== "readme.md")
40
+ .sort((a, b) => a.localeCompare(b))
41
+ .map(name => {
42
+ const filePath = path.join(dir, name)
43
+ const document = readMarkdownDocument(filePath)
44
+ return document ? { name: path.basename(name, ".md"), ...document } : null
45
+ })
46
+ .filter(Boolean)
47
+ }
48
+
49
+ function commandDefinitions(dir) {
50
+ const commands = {}
51
+ for (const doc of readMarkdownDirectory(dir)) {
52
+ const command = {
53
+ description: doc.frontmatter.description || `OpenHermes command ${doc.name}`,
54
+ template: doc.body,
55
+ }
56
+ if (doc.frontmatter.agent) command.agent = doc.frontmatter.agent
57
+ if (doc.frontmatter.model) command.model = doc.frontmatter.model
58
+ if (doc.frontmatter.subtask) command.subtask = doc.frontmatter.subtask === "true"
59
+ commands[doc.name] = command
60
+ }
61
+ return commands
62
+ }
63
+
64
+ function agentDefinitions(dir) {
65
+ const agents = {}
66
+ for (const doc of readMarkdownDirectory(dir)) {
67
+ const name = doc.name === "openhermes" ? OPENHERMES_AGENT : doc.name
68
+ agents[name] = {
69
+ description: doc.frontmatter.description || (name === OPENHERMES_AGENT ? "OpenHermes primary orchestrator" : `OpenHermes agent ${name}`),
70
+ mode: doc.frontmatter.mode || (name === OPENHERMES_AGENT ? "primary" : "subagent"),
71
+ prompt: doc.body,
72
+ }
73
+ }
74
+ return agents
75
+ }
76
+
77
+ function uniqueStrings(existing = [], additions = []) {
78
+ const seen = new Set(existing.filter(Boolean))
79
+ const merged = [...existing]
80
+ for (const item of additions) {
81
+ if (!item || seen.has(item)) continue
82
+ seen.add(item)
83
+ merged.push(item)
84
+ }
85
+ return merged
86
+ }
87
+
88
+ function readText(filePath) {
89
+ return fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : ""
90
+ }
91
+
92
+ function buildBootstrapContent(hDir) {
93
+ const parts = [
94
+ `<${BOOTSTRAP_MARKER}>`,
95
+ `You are OpenHermes.`,
96
+ `OpenHermes is OpenCode-native: load skills on demand, prefer subagents for substantive work, and keep the surface small.`,
97
+ `Durable state is removed for now. Do not invent a persistence layer unless the user explicitly asks for one later.`,
98
+ ]
99
+
100
+ const constitution = readText(path.join(hDir, "codex", "CONSTITUTION.md"))
101
+ const runtime = readText(path.join(hDir, "instructions", "RUNTIME.md"))
102
+ const context = readText(path.join(__dirname, "CONTEXT.md"))
103
+ const ethos = readText(path.join(__dirname, "ETHOS.md"))
104
+
105
+ if (constitution) parts.push(`<CONSTITUTION>\n${constitution}\n</CONSTITUTION>`)
106
+ if (runtime) parts.push(`<RUNTIME>\n${runtime}\n</RUNTIME>`)
107
+ if (context) parts.push(`<CONTEXT>\n${context}\n</CONTEXT>`)
108
+ if (ethos) parts.push(`<ETHOS>\n${ethos}\n</ETHOS>`)
109
+ parts.push(`</${BOOTSTRAP_MARKER}>`)
110
+
111
+ return parts.join("\n\n")
112
+ }
113
+
114
+ export const BootstrapPlugin = async () => {
115
+ const hDir = getHarnessDir()
116
+ const skillsDir = path.join(hDir, "skills")
117
+ const commandsDir = path.join(hDir, "commands")
118
+ const agentsDir = path.join(hDir, "agents")
119
+ const bootstrapContent = buildBootstrapContent(hDir)
120
+
121
+ return {
122
+ config: async (config) => {
123
+ config.skills = config.skills || {}
124
+ config.skills.paths = uniqueStrings(config.skills.paths || [], [skillsDir])
125
+
126
+ config.command = { ...(config.command ?? {}), ...commandDefinitions(commandsDir) }
127
+
128
+ const loadedAgents = agentDefinitions(agentsDir)
129
+ const openHermesAgent = loadedAgents[OPENHERMES_AGENT] ?? {
130
+ description: "OpenHermes primary orchestrator",
131
+ mode: "primary",
132
+ prompt: "You are OpenHermes.",
133
+ }
134
+
135
+ config.agent = {
136
+ ...(config.agent ?? {}),
137
+ ...loadedAgents,
138
+ [OPENHERMES_AGENT]: {
139
+ ...openHermesAgent,
140
+ description: openHermesAgent.description || "OpenHermes primary orchestrator",
141
+ mode: "primary",
142
+ permission: {
143
+ bash: { "*": "allow" },
144
+ edit: "allow",
145
+ read: "allow",
146
+ task: { "*": "allow" },
147
+ },
148
+ },
149
+ }
150
+
151
+ config.default_agent = OPENHERMES_AGENT
152
+
153
+ config.instructions = uniqueStrings(config.instructions || [], [
154
+ path.join(hDir, "codex", "CONSTITUTION.md"),
155
+ path.join(hDir, "instructions", "RUNTIME.md"),
156
+ path.join(__dirname, "CONTEXT.md"),
157
+ path.join(__dirname, "ETHOS.md"),
158
+ ])
159
+ },
160
+
161
+ "experimental.chat.messages.transform": async (_input, output) => {
162
+ try {
163
+ if (!output.messages?.length) return
164
+ const firstUser = output.messages.find(m => m?.info?.role === "user")
165
+ if (!firstUser?.parts?.length) return
166
+ if (firstUser.parts.some(p => p.text?.includes(BOOTSTRAP_MARKER))) return
167
+ const ref = firstUser.parts[0]
168
+ firstUser.parts.unshift({ ...ref, type: "text", text: bootstrapContent })
169
+ } catch (err) {
170
+ log.error("transform error:", err?.message)
171
+ }
172
+ },
173
+ }
174
+ }