openhermes 2.6.1 → 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 -499
  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 -58
  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 -455
  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 -176
  128. package/lib/hardening.mjs +0 -128
  129. package/lib/memory-tools-plugin.mjs +0 -365
  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 -186
  134. package/lib/ohc/message-ids.mjs +0 -168
  135. package/lib/ohc/notify.mjs +0 -154
  136. package/lib/ohc/protected-patterns.mjs +0 -54
  137. package/lib/ohc/prune-apply.mjs +0 -134
  138. package/lib/ohc/pruner.mjs +0 -610
  139. package/lib/ohc/reaper.mjs +0 -70
  140. package/lib/ohc/state.mjs +0 -266
  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 -133
  146. package/lib/paths.mjs +0 -50
  147. package/lib/schema-validator.mjs +0 -77
  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,499 +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
- const HARNESS_DIR = resolveHarnessRoot()
71
- const RULES_DIR = path.join(HARNESS_DIR, "rules")
72
- const SKILLS_DIR = path.join(HARNESS_DIR, "skills")
73
- const CONSTITUTION_FILE = path.join(HARNESS_DIR, "codex", "CONSTITUTION.md")
74
- const RUNTIME_FILE = path.join(HARNESS_DIR, "instructions", "RUNTIME.md")
75
-
76
-
77
- function scanDirNames(dir) {
78
- try { return fs.readdirSync(dir).filter(f => f.endsWith(".md")).map(f => f.replace(/\.md$/, "")).sort() }
79
- catch { return [] }
80
- }
81
-
82
- function scanPromptNames(dir) {
83
- try { return fs.readdirSync(dir).filter(f => f.endsWith('.md') || f.endsWith('.txt')).map(f => path.basename(f, path.extname(f))).sort() }
84
- catch { return [] }
85
- }
86
-
87
- function scanSkillDirs(dir) {
88
- try { return fs.readdirSync(dir).filter(f => fs.statSync(path.join(dir, f)).isDirectory()).sort() }
89
- catch { return [] }
90
- }
91
-
92
- function scanSchemaNames(dir) {
93
- try { return fs.readdirSync(dir).filter(f => f.endsWith(".schema.json")).map(f => f.replace(/\.schema\.json$/, "")).filter(f => f !== "loop-state").sort() }
94
- catch { return [] }
95
- }
96
-
97
- export function buildCapabilityMap(hDir) {
98
- const cmds = scanDirNames(path.join(hDir, "commands"))
99
- if (!cmds.includes("update-me")) cmds.push("update-me")
100
- cmds.sort()
101
-
102
- const agents = scanPromptNames(path.join(hDir, "prompts"))
103
- const skills = scanSkillDirs(path.join(hDir, "skills"))
104
- const schemas = scanSchemaNames(path.join(__dirname, "schemas"))
105
-
106
- return [
107
- "## Capability Map",
108
- "",
109
- `Commands (${cmds.length}): /${cmds.join(" /")}`,
110
- `Subagents (${agents.length}): ${agents.join(" ")}`,
111
- `Skills (${skills.length}): ${skills.join(" ")}`,
112
- `Memory (${schemas.length}): ${schemas.join(" ")}`,
113
- "",
114
- `For problem specialist routing see Delegation below. Skills via \`skill\` tool. Memory via \`ohc_save\` etc.`,
115
- ].join("\n")
116
- }
117
-
118
- export function loadLocalSoulOverride(overridePath) {
119
- const filePath = overridePath || OVERRIDE_SOUL
120
- try {
121
- if (fs.existsSync(filePath)) {
122
- const text = fs.readFileSync(filePath, "utf8").trim()
123
- if (text) return text
124
- }
125
- } catch {}
126
- return null
127
- }
128
-
129
- function buildBootstrapContent() {
130
- let constitution = fs.readFileSync(CONSTITUTION_FILE, "utf8")
131
- const localOverride = loadLocalSoulOverride()
132
- if (localOverride) {
133
- constitution += `\n\n## Local Overrides (survives reinstalls)\n\n${localOverride}`
134
- }
135
- const runtime = fs.readFileSync(RUNTIME_FILE, "utf8")
136
- const capMap = buildCapabilityMap(HARNESS_DIR)
137
-
138
- const router = `## AGENTS.md
139
-
140
- OpenHermes thin constitutional router. Full harness \`${HARNESS_DIR}\\\`.
141
-
142
- ## Constitution
143
-
144
- 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.
145
-
146
- ## Safety
147
-
148
- 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\`).
149
-
150
- ${capMap}
151
-
152
- ## Delegation (Mandatory)
153
-
154
- Main context = coordination + verification only. Substantive work → subagent.
155
-
156
- | Trigger | Subagent |
157
- |---------|----------|
158
- | Multi-file implementation | \`architect\` or \`planner\` |
159
- | Build/TS error | \`build-error-resolver\` |
160
- | Code review | \`code-reviewer\` |
161
- | Security audit | \`security-reviewer\` |
162
- | E2E testing | \`e2e-runner\` |
163
- | Multi-file search/exploration | \`explore\` or \`general\` |
164
- | Documentation lookup | \`docs-lookup\` |
165
- | Doc/codemap update | \`doc-updater\` |
166
- | Dead code cleanup | \`refactor-cleaner\` |
167
- | TDD workflow | \`tdd-guide\` |
168
- | Autonomous loop | \`loop-operator\` |
169
- | Go review | \`review-go\` |
170
- | Go build fix | \`build-go\` |
171
- | Database review | \`review-database\` |
172
- | C++ review | \`review-cpp\` |
173
- | Java review | \`review-java\` |
174
- | Java build fix | \`build-java\` |
175
- | Kotlin review | \`review-kotlin\` |
176
- | Kotlin build fix | \`build-kotlin\` |
177
- | Python review | \`review-python\` |
178
- | Rust review | \`review-rust\` |
179
- | Rust build fix | \`build-rust\` |
180
- | Any non-trivial multi-step | appropriate specialist |
181
-
182
- Never delegate trivial single-step ops. Subagent returns diff + summary + verification; inspect return only. Full ref: \`${RULES_DIR}\\\delegation.md\`.
183
-
184
- ## Handoff Protocol
185
-
186
- 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 \`${RULES_DIR}\\\handoff.md\`.
187
-
188
- - **Act**: Task matches your role and permissions → do it directly
189
- - **Delegate**: Task outside your role → pass to correct agent via \`task\` tool
190
- - **Escalate**: Review/planning agents must NEVER edit code. Delegate to builders.
191
- - **Learn**: After each task, check for repeated patterns. Persist to memory via \`ohc_save\`.
192
- - **Checkpoint**: Before every handoff, save a checkpoint.
193
-
194
- ## Memory — Gated & Precision-First
195
-
196
- - **Start**: Read recall cache first. If stale/missing → \`ohc_latest\` for relevant classes.
197
- - **Before work**: Narrow \`ohc_search\` by class, scope, keywords. Never read full indexes.
198
- - **Before close**: Query same-type mistakes (7 days). Match → \`code-reviewer\` or \`security-reviewer\`.
199
- - **On failure**: \`ohc_search\` for similar incidents. Search memory before asking user.
200
- - **Precision ladder**: \`ohc_latest\` → \`ohc_search\` → \`ohc_get\` → \`ohc_list\` (last resort). Full index reads only for explicit audit/repair tasks.
201
- - **Anti-spam**: No obvious facts, no one-off prefs, no temp state, no low-risk mistakes. Supersede, don't duplicate. Full rules: \`${RULES_DIR}\\\\retrieval.md\`, \`${RULES_DIR}\\\\memory-management.md\`.
202
-
203
- ## Self-Edit Authority
204
-
205
- | Auto | Conditional | Needs approval |
206
- |------|-------------|----------------|
207
- | Memory entries, mistakes, checkpoints, receipts | openhermes docs/schemas/templates/non-core rules patches | AGENTS.md core, model routing, permissions, config, protected settings |
208
-
209
- Full tiers: \`${RULES_DIR}\\\\self-heal.md\`.
210
-
211
- ## Precedence
212
-
213
- 1. User instruction. 2. Safety/legal/destructive guard. 3. Constitution (\`${HARNESS_DIR}\\\\codex\\\`). 4. Project constraints. 5. Project decisions. 6. Verified guards. 7. Checkpoints. 8. Instincts. 9. Freeform notes. Full: \`${RULES_DIR}\\\\precedence.md\`.
214
-
215
- ## Hygiene
216
-
217
- - Checkpoint on meaningful boundaries. Compress closed segments immediately.
218
- - After subagent return: verify → compress that block.
219
- - Compress proactively.
220
- - Skill candidates → \`/learn\` only if repeated pattern + \`ohc_search\` confirms no dup. See \`${RULES_DIR}\\\\skills-management.md\`.
221
- - Audit triggers: openhermes/config change, repeated failures, session start when last audit >7 days. See \`${RULES_DIR}\\\\audit.md\`.
222
-
223
- ## Escalation
224
-
225
- T0: observe → log mistake → smallest fix. T1: add prevention rule → verify. T2: diagnosis/specialist → backlog. T3: constrained safe mode. Full: \`${RULES_DIR}\\\\self-heal.md\`.
226
-
227
- ## State
228
-
229
- - **Config root**: \`%USERPROFILE%\\\\.config\\\\opencode\`
230
- - **Auth**: \`%USERPROFILE%\\\\.local\\\\share\\\\opencode\\\\auth.json\` (NEVER delete)
231
- - **Forensic ledger**: \`%USERPROFILE%\\\\.local\\\\share\\\\opencode\\\\opencode.db\``
232
-
233
- return [
234
- `<OPENHERMES_BOOTSTRAP>\nOpenHermes v${getOwnVersion()} active. Harness: \`${HARNESS_DIR}\\\`. Memory at \`~/.local/share/opencode/openhermes/memory/\`. Rules at \`${RULES_DIR}\\\`. Skills discoverable via \`skill\` tool — use \`skill\` tool to list/load them.`,
235
- `<OPENHERMES_CONSTITUTION>\n${constitution}\n</OPENHERMES_CONSTITUTION>`,
236
- `<OPENHERMES_RUNTIME>\n${runtime}\n</OPENHERMES_RUNTIME>`,
237
- `<OPENHERMES_ROUTER>\n${router}\n</OPENHERMES_ROUTER>`
238
- ].join("\n\n")
239
- }
240
-
241
- function getOwnVersion() {
242
- try {
243
- const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
244
- return pkg.version || "1.0.0"
245
- } catch { return "1.0.0" }
246
- }
247
-
248
- export const BootstrapPlugin = async ({ client, directory }) => {
249
- let _bootstrapCache
250
-
251
- const getContent = () => {
252
- if (_bootstrapCache !== undefined) return _bootstrapCache
253
- try {
254
- _bootstrapCache = buildBootstrapContent()
255
- } catch (err) {
256
- console.error("[openhermes-bootstrap] failed to build bootstrap content:", err.message)
257
- _bootstrapCache = null
258
- }
259
- return _bootstrapCache
260
- }
261
-
262
- return {
263
- config: async (config) => {
264
- config.skills = config.skills || {}
265
- config.skills.paths = config.skills.paths || []
266
- if (!config.skills.paths.includes(SKILLS_DIR)) {
267
- config.skills.paths.push(SKILLS_DIR)
268
- }
269
-
270
- const PROMPTS_DIR = path.join(HARNESS_DIR, "prompts")
271
- const p = (name) => `{file:${path.join(PROMPTS_DIR, name)}}`
272
- const COMMANDS_DIR = path.join(HARNESS_DIR, "commands")
273
- const ct = (file) => `{file:${path.join(COMMANDS_DIR, file)}}\n\n$ARGUMENTS`
274
-
275
- const existingCommands = config.command ?? {}
276
- const existingAgents = { ...(config.agent ?? {}) }
277
-
278
- config.command = {
279
- ...existingCommands,
280
- "build-fix": { agent: "build-error-resolver", description: "Fix build and TypeScript errors", subtask: true, template: ct("build-fix.md") },
281
- "code-review": { agent: "code-reviewer", description: "Review code for quality, security, and maintainability", subtask: true, template: ct("code-review.md") },
282
- "plan": { agent: "planner", description: "Create a detailed implementation plan", subtask: true, template: ct("plan.md") },
283
- "security": { agent: "security-reviewer", description: "Run comprehensive security review", subtask: true, template: ct("security.md") },
284
- "doctor": { agent: "OpenHermes", description: "Run OpenCode OpenHermes health diagnostics", subtask: true, template: ct("doctor.md") },
285
- "memory-search": { agent: "OpenHermes", description: "Search OpenHermes memory with LLM summarization", subtask: true, template: ct("memory-search.md") },
286
- "learn": { agent: "OpenHermes", description: "Create a new skill from recent work patterns", subtask: true, template: ct("learn.md") },
287
- "ohc": { template: "", description: "OHC context management: /ohc status, /ohc compress [focus]" },
288
- "update-me": { template: "", description: "Force reinstall OpenHermes plugin from latest source" },
289
- "orchestrate": { agent: "planner", description: "Orchestrate multiple agents for complex tasks", subtask: true, template: ct("orchestrate.md") },
290
- "eval": { agent: "planner", description: "Evaluate implementation against acceptance criteria", subtask: true, template: ct("eval.md") },
291
- "model-route": { agent: "OpenHermes", description: "Recommend model tier by task complexity and budget", subtask: true, template: ct("model-route.md") },
292
- "quality-gate": { agent: "OpenHermes", description: "Run quality pipeline (format, lint, type check)", subtask: true, template: ct("quality-gate.md") },
293
- "test-coverage": { agent: "tdd-guide", description: "Analyze coverage reports and identify gaps", subtask: true, template: ct("test-coverage.md") },
294
- "update-docs": { agent: "doc-updater", description: "Update documentation for recent code changes", subtask: true, template: ct("update-docs.md") },
295
- "update-codemaps": { agent: "doc-updater", description: "Generate/update architecture codemaps", subtask: true, template: ct("update-codemaps.md") },
296
- "refactor-clean": { agent: "refactor-cleaner", description: "Remove dead code and consolidate duplicates", subtask: true, template: ct("refactor-clean.md") },
297
- "verify": { agent: "OpenHermes", description: "Run comprehensive verification loop (typecheck, lint, test, build)", subtask: true, template: ct("verify.md") },
298
- "checkpoint": { agent: "OpenHermes", description: "Save verification state and progress checkpoint", subtask: true, template: ct("checkpoint.md") },
299
- "loop-start": { agent: "loop-operator", description: "Start managed autonomous loop with safety defaults", subtask: true, template: ct("loop-start.md") },
300
- "loop-status": { agent: "OpenHermes", description: "Inspect active loop state, progress, and failure signals", subtask: true, template: ct("loop-status.md") },
301
- "harness-audit": { agent: "harness-optimizer", description: "Run harness self-audit across 7 categories", subtask: true, template: ct("harness-audit.md") },
302
- "setup-pm": { agent: "OpenHermes", description: "Configure package manager preference for the project", subtask: true, template: ct("setup-pm.md") },
303
- "go-build": { agent: "build-go", description: "Fix Go build, vet, and compilation errors", subtask: true, template: ct("go-build.md") },
304
- "go-review": { agent: "review-go", description: "Review Go code for idiomatic patterns and best practices", subtask: true, template: ct("go-review.md") },
305
- "rust-build": { agent: "build-rust", description: "Fix Rust build, clippy, and dependency errors", subtask: true, template: ct("rust-build.md") },
306
- "rust-review": { agent: "review-rust", description: "Review Rust code for safety, ownership, and idioms", subtask: true, template: ct("rust-review.md") },
307
- "skill-create": { agent: "OpenHermes", description: "Generate a new skill from git history analysis", subtask: true, template: ct("skill-create.md") },
308
- }
309
-
310
- config.experimental ??= {}
311
- config.experimental.primary_tools ??= []
312
- if (!config.experimental.primary_tools.includes("compress")) {
313
- config.experimental.primary_tools.push("compress")
314
- }
315
-
316
- config.agent = {
317
- ...existingAgents,
318
- "OpenHermes": {
319
- description: "Fully autonomous primary coding agent (all tools allowed)",
320
- mode: "primary",
321
- color: "#F59E0B",
322
- permission: {
323
- bash: { "*": "allow" },
324
- edit: "allow",
325
- read: "allow",
326
- task: { "*": "allow" },
327
- },
328
- },
329
- "architect": {
330
- description: "Software architecture specialist for system design",
331
- mode: "subagent",
332
- prompt: p("architect.txt"),
333
- permission: { read: "allow", edit: "deny", bash: "deny" },
334
- },
335
- "build-error-resolver": {
336
- description: "Build and TypeScript error resolution specialist",
337
- mode: "subagent",
338
- prompt: p("build-error-resolver.md"),
339
- permission: { read: "allow", edit: "allow" },
340
- },
341
- "code-reviewer": {
342
- description: "Expert code review specialist",
343
- mode: "subagent",
344
- prompt: p("code-reviewer.md"),
345
- permission: { read: "allow", edit: "deny", bash: "deny", task: { explore: "allow", "*": "deny" } },
346
- },
347
- "e2e-runner": {
348
- description: "End-to-end testing specialist using Playwright",
349
- mode: "subagent",
350
- prompt: p("e2e-runner.txt"),
351
- permission: { read: "allow", edit: "allow" },
352
- },
353
- "explore": {
354
- description: "Fast read-only codebase exploration agent",
355
- mode: "subagent",
356
- prompt: p("explore.md"),
357
- permission: { read: "allow", grep: "allow", glob: "allow", list: "allow", edit: "deny", bash: "deny" },
358
- },
359
- "planner": {
360
- description: "Expert planning specialist for complex features and refactoring",
361
- mode: "subagent",
362
- color: "#3B82F6",
363
- prompt: p("planner.md"),
364
- permission: { read: "allow", edit: "deny", bash: "deny" },
365
- },
366
- "security-reviewer": {
367
- description: "Security vulnerability detection and remediation specialist",
368
- mode: "subagent",
369
- prompt: p("security-reviewer.md"),
370
- permission: { read: "allow", edit: "deny", bash: "deny", task: { "*": "allow" } },
371
- },
372
- "docs-lookup": {
373
- description: "Documentation lookup via MCP — query any library docs in real-time",
374
- mode: "subagent",
375
- prompt: p("docs-lookup.md"),
376
- permission: { read: "allow", bash: "allow", edit: "deny" },
377
- },
378
- "doc-updater": {
379
- description: "Documentation and codemap generation/update specialist",
380
- mode: "subagent",
381
- prompt: p("doc-updater.md"),
382
- permission: { read: "allow", edit: "allow", bash: "allow" },
383
- },
384
- "refactor-cleaner": {
385
- description: "Dead code detection and safe removal specialist",
386
- mode: "subagent",
387
- prompt: p("refactor-cleaner.md"),
388
- permission: { read: "allow", edit: "allow" },
389
- },
390
- "loop-operator": {
391
- description: "Autonomous agent loop operator — safe iteration with stop conditions",
392
- mode: "subagent",
393
- prompt: p("loop-operator.md"),
394
- permission: { read: "allow", edit: "allow", bash: "allow", task: { "*": "allow" } },
395
- },
396
- "harness-optimizer": {
397
- description: "OpenHermes harness configuration optimizer — audit, tune, measure",
398
- mode: "subagent",
399
- prompt: p("harness-optimizer.md"),
400
- permission: { read: "allow", bash: "allow", edit: "deny" },
401
- },
402
- "tdd-guide": {
403
- description: "Test-Driven Development coach — red-green-refactor cycle enforcement",
404
- mode: "subagent",
405
- prompt: p("tdd-guide.md"),
406
- permission: { read: "allow", edit: "allow", bash: "allow" },
407
- },
408
- "review-go": {
409
- description: "Go code review specialist — idiomatic Go, concurrency, error handling",
410
- mode: "subagent",
411
- prompt: p("review-go.md"),
412
- permission: { read: "allow", bash: "allow", edit: "deny" },
413
- },
414
- "build-go": {
415
- description: "Go build error resolution specialist — go build, vet, staticcheck fixes",
416
- mode: "subagent",
417
- prompt: p("build-go.md"),
418
- permission: { read: "allow", edit: "allow", bash: "allow" },
419
- },
420
- "review-database": {
421
- description: "PostgreSQL database specialist — query optimization, schema, RLS, indexes",
422
- mode: "subagent",
423
- prompt: p("review-database.md"),
424
- permission: { read: "allow", bash: "allow", edit: "deny" },
425
- },
426
- "review-cpp": {
427
- description: "C++ code review specialist — memory safety, modern C++, RAII",
428
- mode: "subagent",
429
- prompt: p("review-cpp.md"),
430
- permission: { read: "allow", bash: "allow", edit: "deny" },
431
- },
432
- "build-cpp": {
433
- description: "C++ build error resolution specialist — CMake, linker, template errors",
434
- mode: "subagent",
435
- prompt: p("build-cpp.md"),
436
- permission: { read: "allow", edit: "allow", bash: "allow" },
437
- },
438
- "review-java": {
439
- description: "Java/Spring Boot review specialist — JPA, architecture, security",
440
- mode: "subagent",
441
- prompt: p("review-java.md"),
442
- permission: { read: "allow", bash: "allow", edit: "deny" },
443
- },
444
- "build-java": {
445
- description: "Java/Maven/Gradle build error resolution specialist",
446
- mode: "subagent",
447
- prompt: p("build-java.md"),
448
- permission: { read: "allow", edit: "allow", bash: "allow" },
449
- },
450
- "review-kotlin": {
451
- description: "Kotlin/Android review specialist — coroutines, Compose, architecture",
452
- mode: "subagent",
453
- prompt: p("review-kotlin.md"),
454
- permission: { read: "allow", bash: "allow", edit: "deny" },
455
- },
456
- "build-kotlin": {
457
- description: "Kotlin/Gradle build error resolution specialist",
458
- mode: "subagent",
459
- prompt: p("build-kotlin.md"),
460
- permission: { read: "allow", edit: "allow", bash: "allow" },
461
- },
462
- "review-python": {
463
- description: "Python code review specialist — PEP 8, type hints, security",
464
- mode: "subagent",
465
- prompt: p("review-python.md"),
466
- permission: { read: "allow", bash: "allow", edit: "deny" },
467
- },
468
- "review-rust": {
469
- description: "Rust code review specialist — ownership, lifetimes, safety",
470
- mode: "subagent",
471
- prompt: p("review-rust.md"),
472
- permission: { read: "allow", bash: "allow", edit: "deny" },
473
- },
474
- "build-rust": {
475
- description: "Rust build error resolution specialist — cargo, borrow checker, clippy",
476
- mode: "subagent",
477
- prompt: p("build-rust.md"),
478
- permission: { read: "allow", edit: "allow", bash: "allow" },
479
- },
480
- }
481
-
482
- config.default_agent = "OpenHermes"
483
- },
484
-
485
- "experimental.chat.messages.transform": async (_input, output) => {
486
- try {
487
- const bootstrap = getContent()
488
- if (!bootstrap || !output.messages || !output.messages.length) return
489
- const firstUser = output.messages.find(m => m && m.info && m.info.role === "user")
490
- if (!firstUser || !firstUser.parts || !firstUser.parts.length) return
491
- if (firstUser.parts.some(p => p.type === "text" && p.text.includes("OPENHERMES_BOOTSTRAP"))) return
492
- const ref = firstUser.parts[0]
493
- firstUser.parts.unshift({ ...ref, type: "text", text: bootstrap })
494
- } catch (err) {
495
- console.error("[openhermes-bootstrap] transform error:", err.message)
496
- }
497
- }
498
- }
499
- }
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
+ }