openhermes 1.13.1 → 2.5.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 (78) hide show
  1. package/README.md +125 -206
  2. package/autorecall.mjs +79 -12
  3. package/bootstrap.mjs +122 -25
  4. package/curator.mjs +4 -40
  5. package/harness/commands/harness-audit.md +1 -1
  6. package/harness/commands/learn.md +2 -2
  7. package/harness/commands/memory-search.md +2 -2
  8. package/harness/constitution/soul.md +16 -4
  9. package/harness/instructions/RUNTIME.md +6 -3
  10. package/harness/prompts/architect.txt +14 -0
  11. package/harness/prompts/build-cpp.md +15 -1
  12. package/harness/prompts/build-error-resolver.md +15 -9
  13. package/harness/prompts/build-go.md +14 -0
  14. package/harness/prompts/build-java.md +15 -1
  15. package/harness/prompts/build-kotlin.md +15 -1
  16. package/harness/prompts/build-rust.md +14 -0
  17. package/harness/prompts/code-reviewer.md +15 -9
  18. package/harness/prompts/doc-updater.md +13 -0
  19. package/harness/prompts/docs-lookup.md +11 -0
  20. package/harness/prompts/e2e-runner.txt +12 -0
  21. package/harness/prompts/explore.md +16 -4
  22. package/harness/prompts/harness-optimizer.md +12 -0
  23. package/harness/prompts/loop-operator.md +11 -0
  24. package/harness/prompts/planner.md +15 -9
  25. package/harness/prompts/refactor-cleaner.md +14 -0
  26. package/harness/prompts/review-cpp.md +14 -1
  27. package/harness/prompts/review-database.md +13 -0
  28. package/harness/prompts/review-go.md +13 -0
  29. package/harness/prompts/review-java.md +14 -1
  30. package/harness/prompts/review-kotlin.md +13 -0
  31. package/harness/prompts/review-python.md +14 -1
  32. package/harness/prompts/review-rust.md +13 -0
  33. package/harness/prompts/security-reviewer.md +15 -9
  34. package/harness/prompts/tdd-guide.md +14 -0
  35. package/harness/rules/audit.md +2 -2
  36. package/harness/rules/delegation.md +0 -2
  37. package/harness/rules/handoff.md +267 -0
  38. package/harness/rules/memory-management.md +4 -4
  39. package/harness/rules/precedence.md +1 -1
  40. package/harness/rules/retrieval.md +5 -5
  41. package/harness/rules/runtime-guards.md +1 -1
  42. package/harness/rules/self-heal.md +1 -1
  43. package/harness/rules/session-start.md +5 -5
  44. package/harness/rules/skills-management.md +2 -2
  45. package/harness/rules/verification.md +4 -4
  46. package/index.mjs +6 -2
  47. package/lib/ambient-memory.mjs +167 -0
  48. package/lib/handoff.mjs +176 -0
  49. package/lib/hardening.mjs +13 -8
  50. package/lib/memory-tools-plugin.mjs +107 -54
  51. package/lib/ohc/block-sync.mjs +69 -0
  52. package/lib/ohc/compress/search.mjs +152 -0
  53. package/lib/ohc/compress/state.mjs +76 -0
  54. package/lib/ohc/config.mjs +172 -16
  55. package/lib/ohc/message-ids.mjs +168 -0
  56. package/lib/ohc/notify.mjs +150 -0
  57. package/lib/ohc/protected-patterns.mjs +54 -0
  58. package/lib/ohc/prune-apply.mjs +134 -0
  59. package/lib/ohc/pruner.mjs +406 -55
  60. package/lib/ohc/reaper.mjs +12 -3
  61. package/lib/ohc/state.mjs +246 -15
  62. package/lib/ohc/strategies/deduplication.mjs +72 -0
  63. package/lib/ohc/strategies/index.mjs +2 -0
  64. package/lib/ohc/strategies/purge-errors.mjs +43 -0
  65. package/lib/ohc/token-utils.mjs +26 -0
  66. package/lib/ohc/updater.mjs +36 -13
  67. package/lib/paths.mjs +0 -3
  68. package/lib/search.mjs +48 -0
  69. package/package.json +1 -1
  70. package/schemas/audit.schema.json +22 -1
  71. package/schemas/backlog.schema.json +23 -2
  72. package/schemas/checkpoint.schema.json +23 -2
  73. package/schemas/constraint.schema.json +23 -2
  74. package/schemas/decision.schema.json +23 -2
  75. package/schemas/instinct.schema.json +23 -2
  76. package/schemas/mistake.schema.json +23 -2
  77. package/schemas/verification_receipt.schema.json +23 -2
  78. package/skill-builder.mjs +12 -23
package/README.md CHANGED
@@ -12,185 +12,106 @@
12
12
 
13
13
  ---
14
14
 
15
- **Your OpenCode agent, leveled up.** Add it to your plugins and your agent gains a personality, a memory, a conscience, 25 specialist subagents, 28 slash commands, 6 native memory tools, 10 procedural skills, autonomous checkpointing, and the discipline to self-improve.
16
-
17
15
  ```bash
18
16
  npm i openhermes
19
17
  ```
20
18
 
21
- ---
19
+ **One install. Your agent gains a personality, memory, 25 specialist subagents, 28 commands, structured handoff protocol, and the discipline to self-improve.**
22
20
 
23
- > ☤ **Inspired by [Hermes Agent](https://github.com/NousResearch/hermes-agent)** — Nous Research's self-improving agent that brought closed learning loops, skill creation, and cross-session memory to the agent ecosystem. OpenHermes reimagines that vision **native to the OpenCode platform**: zero dependencies, no sidecars, no installers. Your entire agent OS in a single npm package.
24
- >
25
- > **Pruning inspiration**: The autonomous context-pressure system is heavily inspired by [Opencode-DCP (Dynamic Context Pruning)](https://github.com/Opencode-DCP/opencode-dynamic-context-pruning). The curator plugin's compaction-trigger logic and recall-cache freshness model are direct ports of DCP's approach, adapted to run inside OpenHermes with no sidecars or installers.
26
- >
27
- > **Subagent & command expansion**: The 18 language-specialist subagents and 19 orchestration commands are adapted from [Everything Claude Code (ECC)](https://github.com/everything-claude-code/ecc) an open-source OpenCode plugin system.
21
+ ```json
22
+ { "plugin": ["openhermes"] }
23
+ ```
24
+
25
+ No Python. No Docker. No cron. No database. Just Node.js and your existing OpenCode runtime.
28
26
 
29
27
  ---
30
28
 
31
29
  ## What OpenHermes Does For Your Agent
32
30
 
33
31
  <table>
34
- <tr><td width="160"><b>&#129302; Personality Layer</b></td><td>An 11-principle constitution (<code>soul.md</code>) injected into every session — pragmatic, concise, subagent-first, verify-don't-claim. Your agent stops rambling and starts delivering.</td></tr>
35
- <tr><td><b>&#128204; Delegation Discipline</b></td><td>Mandated routing table every non-trivial task goes to the right specialist subagent. Main context stays clean, coordination-only. No more bloated chat logs.</td></tr>
36
- <tr><td><b>&#128190; 9-Class Durable Memory</b></td><td>Checkpoints, decisions, constraints, instincts, mistakes, backlog items, audit reports, verification receipts, and session recall — all schema-validated, fingerprint-aware, persisted to disk.</td></tr>
37
- <tr><td><b>&#129520; Precision-First Retrieval</b></td><td>Gated retrieval with anti-spam controls. <code>latest_memory</code> <code>search_memory</code> <code>fetch_memory</code> <code>list_memory</code>. No full-index reads unless explicitly scoped. Memory stays lean.</td></tr>
38
- <tr><td><b>&#128293; Autonomous Checkpointing</b></td><td>Pre-compaction snapshots capture mission, current state, next actions, blockers, and risk notes so compaction never loses the plot.</td></tr>
39
- <tr><td><b>&#128260; Closed Learning Loop</b></td><td>Mistakes are logged with root cause + prevention rule. Complex sessions auto-generate skill-candidate backlogs. Strike tracking escalates repeat failures. The agent gets better you don't have to teach it twice.</td></tr>
40
- <tr><td><b>&#128736; 10 Bundled Procedural Skills</b></td><td>Pre-built skills for API design, backend patterns, coding standards, E2E testing, frontend patterns, frontend slides, security reviews, strategic compaction, TDD workflow, and verification loops. Discovered automatically — use <code>skill</code> to list and load.</td></tr>
41
- <tr><td><b>&#128270; Context Pruner</b></td><td>Agent-controlled compression via <code>ohc.json</code> (soft defaults) + <code>compress</code> tool with <code>targetTokens</code> override. No token claims — reports message count only. Recommend <code>compaction.auto: false</code> to prevent double pruning with OpenCode's built-in system.</td></tr>
42
- <tr><td><b>&#129513; Zero Infrastructure</b></td><td>No Python. No uv. No Docker. No PostgreSQL. No gateway. No cron daemon. Just Node.js and your existing OpenCode runtime.</td></tr>
32
+ <tr><td width="180"><b>&#129302; Constitutional Spine</b></td><td>An 11-principle constitution (<code>soul.md</code>) injected into every session — pragmatic, concise, subagent-first, verify-don't-claim. Your agent stops rambling and starts delivering.</td></tr>
33
+ <tr><td><b>&#128204; Structured Handoff Protocol</b></td><td>Every agent knows its permission tier and handoff triggers. Review agents never edit. Builders never approve their own work. Security reports only. Tasks are complexity-graded (easy → very-large) and routed to the right specialist automatically.</td></tr>
34
+ <tr><td><b>&#128190; 9-Class Durable Memory</b></td><td>Checkpoints, decisions, constraints, instincts, mistakes, backlog items, audit reports, verification receipts, and session recall — all schema-validated, fingerprint-aware, persisted to disk. Retrieval is gated and precision-first.</td></tr>
35
+ <tr><td><b>&#128260; Closed Learning Loop</b></td><td>Mistakes are logged with root cause + prevention rule. Complex sessions auto-generate skill-candidate backlogs. Strike tracking escalates repeat failures into structural fixes. The agent gets better — you don't teach it twice.</td></tr>
36
+ <tr><td><b>&#128736; 10 Bundled Procedural Skills</b></td><td>Pre-built skills for API design, backend patterns, coding standards, E2E testing, frontend patterns, frontend slides, security reviews, strategic compaction, TDD workflow, and verification loops. Auto-discovered — use <code>skill</code> to list and load.</td></tr>
37
+ <tr><td><b>&#128270; Context Pruner</b></td><td>Agent-controlled compression via <code>ohc.json</code> + <code>compress</code> tool. Progressive nudges at 70/85/95%. No token claimsreports message count only.</td></tr>
38
+ <tr><td><b>&#129513; Zero Infrastructure</b></td><td>No Python. No uv. No Docker. No PostgreSQL. No gateway. No cron daemon. No MCP server. Just Node.js and your existing OpenCode runtime.</td></tr>
43
39
  </table>
44
40
 
45
41
  ---
46
42
 
47
- ## Setup
43
+ ## Agent Handoff Protocol — New in v2.5
48
44
 
49
- Add one line to your `opencode.json`. Two good options:
45
+ The reason most agent sessions descend into chaos: every agent thinks it can do everything. OpenHermes fixes that with a **structured handoff system** baked into every subagent prompt.
50
46
 
51
- ### Published Release
47
+ **Coverage:** All 25 subagents now include standard Permissions and Handoff sections. Each agent knows its tier (1/2/3), what actions it can take, when to delegate, and how to format a handoff request.
52
48
 
53
- Use npm when you want a stable release boundary.
49
+ **Complexity-gated routing:**
54
50
 
55
- ```json
56
- {
57
- "plugin": ["openhermes"]
58
- }
59
- ```
51
+ | Level | Criteria | Strategy |
52
+ |-------|----------|----------|
53
+ | **Easy** | 1-2 files, well-known pattern, single change | Handle directly |
54
+ | **Medium** | 3-10 files, new feature, needs exploration | 2-5 subagents, sequential or fan-out |
55
+ | **Hard** | 10+ files, cross-cutting change | Sequential: planner → executor → reviewers |
56
+ | **Very Large** | 50+ files, massive refactor | Fan-out: split into chunks, parallel, consolidate |
57
+
58
+ **Permission tiers:**
59
+
60
+ | Tier | Agents | Can edit? | Can exec? | Can review? |
61
+ |------|--------|-----------|-----------|-------------|
62
+ | 1 | planners, architects, reviewers, explore | ❌ | ❌ | ✅ |
63
+ | 2 | builders, doc-updaters, refactor-cleaners | ✅ | ✅ | ❌ (own work) |
64
+ | 3 | primary agent, loop-operator, e2e-runner | ✅ | ✅ | ✅ |
65
+
66
+ **Built library** — `lib/handoff.mjs` (136 lines, 5 exports): `handoffRequest`, `parseHandoffResult`, `assessComplexity`, `suggestAgent`, `canAgent`. Simple enough to audit. Sophisticated enough to govern 25 agents.
67
+
68
+ ---
60
69
 
61
- ### Git-Backed
70
+ ## Setup
71
+
72
+ Add one line to your `opencode.json`:
62
73
 
63
- Use GitHub when you want the latest pushed changes immediately.
74
+ ### Published Release (stable)
75
+ ```json
76
+ { "plugin": ["openhermes"] }
77
+ ```
64
78
 
79
+ ### Git-Backed (latest pushed changes)
65
80
  ```json
66
- {
67
- "plugin": ["openhermes@git+https://github.com/nathwn12/openhermes.git"]
68
- }
81
+ { "plugin": ["openhermes@git+https://github.com/nathwn12/openhermes.git"] }
69
82
  ```
70
83
 
71
84
  Either way, **no other config needed.** The plugin auto-registers:
72
85
 
73
86
  | What | Details |
74
87
  |------|---------|
75
- | **25 subagents** | 7 core + 18 specialist:<br>**Core:** architect, planner, build-error-resolver, code-reviewer, security-reviewer, e2e-runner, explore<br>**Specialist:** tdd-guide, docs-lookup, doc-updater, refactor-cleaner, loop-operator, harness-optimizer, review-go, build-go, review-rust, build-rust, review-python, review-java, build-java, review-kotlin, build-kotlin, review-cpp, build-cpp, review-database |
88
+ | **25 subagents** | 7 core (architect, planner, build-error-resolver, code-reviewer, security-reviewer, e2e-runner, explore) + 18 specialist (tdd-guide, docs-lookup, doc-updater, refactor-cleaner, loop-operator, harness-optimizer, 9 language-specific build/review pairs, review-database) |
76
89
  | **28 slash commands** | `/build-fix`, `/checkpoint`, `/code-review`, `/doctor`, `/eval`, `/go-build`, `/go-review`, `/harness-audit`, `/learn`, `/loop-start`, `/loop-status`, `/memory-search`, `/model-route`, `/ohc`, `/orchestrate`, `/plan`, `/quality-gate`, `/refactor-clean`, `/rust-build`, `/rust-review`, `/security`, `/setup-pm`, `/skill-create`, `/test-coverage`, `/update-codemaps`, `/update-docs`, `/update-me`, `/verify` |
77
- | **6 native memory tools** | `add_memory`, `fetch_memory`, `list_memory`, `latest_memory`, `search_memory`, `archive_memory` — in-process, no MCP server needed |
90
+ | **6 native memory tools** | `ohc_save`, `ohc_get`, `ohc_list`, `ohc_latest`, `ohc_search`, `ohc_archive` — in-process, no MCP server |
78
91
  | **10 procedural skills** | API design, backend patterns, coding standards, E2E testing, frontend patterns, frontend slides, security review, strategic compaction, TDD workflow, verification loop |
79
92
  | **6 lifecycle plugins** | bootstrap, curator, autorecall, skill-builder, memory-tools, ohc |
80
93
 
81
- You only need to define primary agents (like `build` or `OpenHermes`) in `opencode.json` subagents are injected automatically.
82
-
83
- > **🔄 Force update / repair:** Run `/update-me` anytime to clear the cached OpenHermes and reload from source. Works with both git-backed and npm installs. Use when the plugin feels stale, broken, or you just pushed changes upstream.
94
+ > **&#128260; Force update:** Run `/update-me` anytime to clear stale cache and reload from source. Works with both git-backed and npm installs.
84
95
 
85
96
  <details>
86
97
  <summary><b>What happens on your next session</b></summary>
87
98
 
88
- 1. **Config hook** — BootstrapPlugin registers auto-config: 25 subagents, 28 commands, 10 skill dirs.
89
- 2. **Chat transform hook** — bootstrap content is injected into the first user message:
90
- - &#9733; **Constitution** (`soul.md`) 11 immutable principles
91
- - &#9733; **Runtime** (`RUNTIME.md`) gather delegate verify compress
92
- - &#9733; **Router** (`AGENTS.md`) delegation table, memory policy, escalation, and rule paths
93
- 3. **Session created** — AutorecallPlugin builds recall cache from prior session memory.
94
- 4. **Tools execute** — SkillBuilderPlugin watches tool calls and subagent spawns; MemoryToolsPlugin provides 5 native tools immediately.
95
- 5. **Session idle** — CuratorPlugin snapshots checkpoint + verification receipt.
96
- 6. **Session error** — CuratorPlugin logs mistake with root cause + prevention rule.
97
- 7. **Compaction** — CuratorPlugin force-writes a pre-compaction checkpoint and injects state into the compaction buffer.
98
-
99
- The LLM reads rules on demand via the injected paths. Memory directories auto-create. Everything Just Works.
99
+ 1. **Config hook** — BootstrapPlugin registers 25 subagents, 28 commands, 10 skill paths
100
+ 2. **Chat transform** — Constitution + Runtime + Router injected into first user message
101
+ 3. **Session created** — AutorecallPlugin builds recall cache from prior session memory
102
+ 4. **Tools execute** — SkillBuilderPlugin watches calls; MemoryToolsPlugin provides 6 native tools immediately
103
+ 5. **Session idle** — CuratorPlugin snapshots checkpoint + verification receipt
104
+ 6. **Session error** — CuratorPlugin logs mistake with root cause + prevention rule
105
+ 7. **Compaction** — CuratorPlugin force-writes pre-compaction checkpoint and injects state into compaction buffer
100
106
 
107
+ No polling. No cron. Six plugins, 20+ hooks, one runtime.
101
108
  </details>
102
109
 
103
110
  ---
104
111
 
105
- ## Context Pruner (OHC)
106
-
107
- ### Required: disable OpenCode's built-in compaction
108
-
109
- Add to your `opencode.json` to prevent double pruning:
110
-
111
- ```json
112
- {
113
- "compaction": {
114
- "auto": false
115
- }
116
- }
117
- ```
118
-
119
- See [OpenCode compaction docs](https://opencode.ai/docs/config/#compaction).
120
-
121
- ### Configure OHC
122
-
123
- Config lives at `~/.config/opencode/ohc.json` — auto-generated with defaults on first load if missing:
124
-
125
- ```json
126
- {
127
- "enabled": true,
128
- "max": 200000,
129
- "min": 50000
130
- }
131
- ```
132
-
133
- | Field | Default | Job |
134
- |-------|---------|-----|
135
- | `enabled` | `true` | Master switch |
136
- | `max` | `200000` | Advisory prune threshold (soft — agent can override) |
137
- | `min` | `50000` | Advisory token floor (soft — agent can override via `targetTokens`) |
138
-
139
- Values are **soft defaults** — the agent has full control. When the user asks "compress to X", pass `targetTokens` to the `compress` tool.
140
-
141
- System prompt is injected with your budget and floor. As context grows, progressive nudges appear at 70%, 85%, and 95% urging proactive compression. Use `/ohc compress [focus]` or call the `compress` tool to free space on demand.
142
-
143
- **Commands:**
144
- - `/ohc status` — show current context usage
145
- - `/ohc compress [targetTokens] [focus]` — queue compression with optional numeric target
146
-
147
- **Compress tool:** LLM-available. Call `compress` with a technical summary and optional `targetTokens` (lower = more aggressive). Token counts are rough estimates — the tool reports message count removed, not token savings.
148
-
149
- ---
150
-
151
- ## The Seven Plugins
152
-
153
- ### BootstrapPlugin
154
- _Registers agents, commands, skills at config hook; injects constitution + router + runtime into every session._
155
- - **Hooks:** `config`, `chat.transform`
156
- - Registers 25 subagents, 28 commands, 10 skill paths
157
-
158
- ### MemoryToolsPlugin
159
- _Provides 6 native memory tools — no MCP server, no network, no sidecars._
160
- - Registers `add_memory`, `fetch_memory`, `list_memory`, `latest_memory`, `search_memory`, `archive_memory`
161
-
162
- ### CuratorPlugin
163
- _Snapshots state, logs mistakes, records decisions — the agent's durable memory layer._
164
- - **Hooks:** `session.idle`, `.error`, `.compacted`, `.compacting`, `permission.replied`
165
- - Writes checkpoints, logs mistakes with root cause + prevention, records audits, injects state into compaction
166
-
167
- ### AutorecallPlugin
168
- _Loads prior session memory into recall cache at startup._
169
- - **Hooks:** `session.created`
170
- - Builds recall cache from disk, aggregates active state for compaction injection
171
-
172
- ### SkillBuilderPlugin
173
- _Auto-detects complex sessions and creates skill-candidate backlogs._
174
- - **Hooks:** `session.created`, `session.idle`, `tool.execute.after`
175
- - Tracks tool call count and subagent spawns per session; flags sessions exceeding threshold (8+ tool calls or 2+ subagent spawns)
176
-
177
- ### OhcPlugin
178
- _Silent config-driven context pruner. No tool calls, no chat output, no toasts._
179
- - **Hooks:** `config`, `experimental.chat.system.transform`, `.messages.transform`, `command.execute.before`, `tool.compress`
180
- - Injects context budget via system prompt; progressive nudges at 70%/85%/95%; silent reaper enforces hard limit; `/ohc` command + `compress` tool for on-demand pruning
181
-
182
- ### UpdaterPlugin
183
- _Force-update / repair command for OpenHermes itself._
184
- - **Hooks:** `command.execute.before`
185
- - Registers `/update-me` — detects install method (git or npm), clears stale cache, tells user to restart. Safe to run anytime.
186
-
187
- ---
188
-
189
112
  ## Memory Architecture
190
113
 
191
- Nine schema-validated classes across two dimensions what the record is and where it lives.
192
-
193
- ### Classes
114
+ Nine schema-validated classes. All scrubbed of proto-poison, secrets, and overflow before hitting disk.
194
115
 
195
116
  | Class | Format | Layer | Purpose |
196
117
  |-------|--------|-------|---------|
@@ -204,50 +125,58 @@ Nine schema-validated classes across two dimensions — what the record is and w
204
125
  | `verification_receipt` | JSON | ✅ Integrity | Cached verification results keyed by artifact fingerprint |
205
126
  | `recall` | JSON | ✅ Integrity | Session-start cache for compaction buffer injection |
206
127
 
207
- ### Storage
208
-
209
- | What | Where |
210
- |------|-------|
211
- | OHC config | `~/.config/opencode/ohc.json` |
212
- | Durable memory + runtime state | `~/.local/share/opencode/openhermes/` |
213
- | Derived recall cache | `~/.cache/opencode/openhermes/recall/` |
128
+ **Storage:** `~/.local/share/opencode/openhermes/` for durable memory, `~/.cache/opencode/openhermes/recall/` for derived cache, `~/.config/opencode/ohc.json` for pruner config.
214
129
 
215
- ### Hardening
130
+ **Retrieval ladder:** `ohc_latest` → `ohc_search` → `ohc_get` → `ohc_list`. Anti-spam: no obvious facts, no one-off prefs, no low-risk mistakes. Memory stays lean or it gets archived.
216
131
 
217
- Every record is scrubbed before persistence: `sanitizeRecord()` strips proto-poison (`__proto__`, `constructor`, `prototype`), `redactSensitiveText()` strips bearer tokens / API keys / passwords, `truncateText()` caps field sizes. Schema validation runs before every write.
132
+ **Hardening:** Every record is sanitized, redacted, truncated, and validated before write. Proto-poison (`__proto__`, `constructor`, `prototype`) stripped. Bearer tokens / API keys / passwords redacted. Fields capped by schema limits.
218
133
 
219
134
  ---
220
135
 
221
- ## Session Lifecycle
136
+ ## Self-Healing Escalation
222
137
 
223
- A session runs through three phases. Six plugins coordinate across 20+ OpenCode hooks no polling, no cron, no sidecars.
138
+ A mistake is not a failure it's a signal. OpenHermes escalates through four tiers before it ever reaches you.
224
139
 
225
- **▶️ Warmup — one-shot, session start**
226
- ```
227
- config hook BootstrapPlugin registers harness/skills/, skills auto-discover
228
- session.created BootstrapPlugin injects constitution ▸ router ▸ runtime
229
- AutorecallPlugin loads disk memory → writes recall cache
230
- SkillBuilderPlugin resets counters
231
140
  ```
141
+ T0 ── Any mistake
142
+ Observe → log mistake record → smallest safe correction → verify
232
143
 
233
- **⚙️ Execution per tool call, per subagent spawn**
234
- ```
235
- tool.execute.* SkillBuilderPlugin counts calls + spawns
236
- ```
144
+ T1 ── Same mistake repeats within 7 days
145
+ Add prevention rule → targeted verification
237
146
 
238
- **⏹️ Cooldown auto-triggered by OpenCode lifecycle**
147
+ T2 ── Prevention failed / systemic issue
148
+ Delegate to specialist → deep audit → backlog item → structural fix
149
+
150
+ T3 ── Cascading failures
151
+ Constrained safe mode: narrow claims, preserve receipts, produce handoff
239
152
  ```
240
- session.idle CuratorPlugin: checkpoint snapshot + verification receipt
241
- SkillBuilderPlugin: complexity check → backlog candidate
242
153
 
243
- session.compacting CuratorPlugin: force-writes pre-compaction checkpoint
244
- Injects harness state + recall context → compaction buffer
154
+ No self-termination. No grandstanding. The agent gets better — you don't teach it twice.
245
155
 
246
- session.compacted CuratorPlugin: updates loop-state to "compacted"
156
+ ---
157
+
158
+ ## Session Lifecycle
247
159
 
248
- session.error CuratorPlugin: logs mistake (type, root cause, fix, prevention)
160
+ Three phases. Six plugins coordinate across 20+ OpenCode hooks.
249
161
 
250
- permission.replied CuratorPlugin: writes audit record for every permission decision
162
+ ```
163
+ ▶️ Warmup
164
+ config hook BootstrapPlugin registers harness/skills/, skills auto-discover
165
+ session.created BootstrapPlugin injects constitution → router → runtime
166
+ AutorecallPlugin loads disk memory → writes recall cache
167
+ SkillBuilderPlugin resets counters
168
+
169
+ ⚙️ Execution
170
+ tool.execute.* SkillBuilderPlugin counts calls + spawns
171
+
172
+ ⏹️ Cooldown
173
+ session.idle CuratorPlugin: checkpoint snapshot + verification receipt
174
+ SkillBuilderPlugin: complexity check → backlog candidate
175
+ session.compacting CuratorPlugin: force-writes pre-compaction checkpoint
176
+ Injects harness state + recall context → compaction buffer
177
+ session.compacted CuratorPlugin: updates loop-state to "compacted"
178
+ session.error CuratorPlugin: logs mistake (type, root cause, fix, prevention)
179
+ permission.replied CuratorPlugin: writes audit record for every permission decision
251
180
  ```
252
181
 
253
182
  ---
@@ -264,7 +193,7 @@ One core habit — **verify before claiming success.**
264
193
  | 🔄 Re-verify on change | Stale receipt is worse than no receipt |
265
194
  | 🚩 Flag contradictions | Silence is consent to bugs |
266
195
 
267
- Verification receipts are a first-class memory type — keyed by artifact identity + fingerprint (path, mtime, hash). When the artifact is unchanged, the cached receipt suffices. When the artifact changes, re-verify. This is not an afterthought — it's the difference between "I think it works" and "I know it works."
196
+ Verification receipts are a first-class memory type — keyed by artifact identity + fingerprint (path, mtime, hash). This is not an afterthought. It's the difference between "I think it works" and "I know it works."
268
197
 
269
198
  ---
270
199
 
@@ -272,11 +201,11 @@ Verification receipts are a first-class memory type — keyed by artifact identi
272
201
 
273
202
  The full operational doctrine ships inside the package. Six directories, zero dependencies outside Node.js.
274
203
 
275
- | Directory | What it contains | Why it matters |
276
- |-----------|-----------------|----------------|
204
+ | Directory | Contents | Purpose |
205
+ |-----------|----------|---------|
277
206
  | `constitution/` | `soul.md` — 11 immutable principles | Your agent's personality, frozen |
278
207
  | `instructions/` | Runtime workflow + coding conventions | The playbook every session runs on |
279
- | `rules/` | 16 files: retrieval, verification, audit, self-heal, delegation, ... | The legal framework — no ambiguity |
208
+ | `rules/` | 17 files: retrieval, verification, audit, self-heal, delegation, handoff | The legal framework — no ambiguity |
280
209
  | `skills/` | 10 procedural SKILL.md files | Domain expertise discovered automatically |
281
210
  | `prompts/` | 25 subagent prompt templates | Language specialists, docs lookup, loop drivers — all on tap |
282
211
  | `commands/` | 26 slash command templates | From `/verify` to `/review-go` — full toolbelt |
@@ -285,42 +214,20 @@ OpenHermes is not a runtime shim. The doctrine ships with the package — every
285
214
 
286
215
  ---
287
216
 
288
- ## Self-Healing Escalation
289
-
290
- A mistake is not a failure — it's a signal. OpenHermes escalates through four tiers before it ever reaches you.
291
-
292
- ```
293
- T0 ── Any mistake
294
- Observe → log mistake record → smallest safe correction → verify
295
-
296
- T1 ── Same mistake repeats within 7 days
297
- Add prevention rule → targeted verification
298
-
299
- T2 ── Prevention failed / systemic issue
300
- Delegate to specialist → deep audit → backlog item
301
-
302
- T3 ── Cascading failures
303
- Constrained safe mode: narrow claims, preserve receipts, produce handoff
304
- ```
305
-
306
- No self-termination. No grandstanding. Narrow, log, recover, improve. The agent gets better — you don't have to teach it twice.
307
-
308
- ---
309
-
310
- ## Environment Variables
217
+ ## The Six Plugins
311
218
 
312
- Two knobs. That's it.
313
-
314
- | Variable | Default | Effect |
315
- |----------|---------|--------|
316
- | `OPENCODE_ALLOW_PROJECT_HARNESS` | `false` | Enable project-local harness at `.opencode/openhermes/` |
317
- | `OPENCODE_CURATOR_LOGS` | `false` | Pipe curator diagnostics to stderr for debugging |
219
+ | Plugin | Hook Points | Job |
220
+ |--------|-------------|-----|
221
+ | **Bootstrap** | `config`, `chat.transform` | Registers agents/commands/skills; injects constitution + router + runtime |
222
+ | **MemoryTools** | (tool registration) | Provides 6 `ohc_*` tools — no MCP server, no network |
223
+ | **Curator** | `session.idle`, `.error`, `.compacted`, `.compacting`, `permission.replied` | Snapshots state, logs mistakes, records decisions, injects into compaction |
224
+ | **Autorecall** | `session.created` | Loads prior session memory into recall cache at startup |
225
+ | **SkillBuilder** | `session.created`, `.idle`, `tool.execute.after` | Auto-detects complex sessions (8+ calls or 2+ spawns) → backlog candidates |
226
+ | **OhcPlugin** | `config`, all transform/command hooks | Silent context pruner; injects budget; progressive nudges; `/ohc` command + `compress` tool |
318
227
 
319
228
  ---
320
229
 
321
- ## Architecture
322
-
323
- Three layers. All ES modules. One runtime dependency.
230
+ ## Architecture — Three Layers, One Dependency
324
231
 
325
232
  ```
326
233
  openhermes/
@@ -333,6 +240,7 @@ openhermes/
333
240
 
334
241
  ├── ⚡ lib/
335
242
  │ ├── memory-tools-plugin.mjs # 5 hm_* tools
243
+ │ ├── handoff.mjs # Structured delegation protocol
336
244
  │ ├── hardening.mjs # sanitize, redact, atomic write
337
245
  │ ├── paths.mjs # storage root resolver
338
246
  │ ├── schema-validator.mjs # Draft-07 validation
@@ -343,7 +251,7 @@ openhermes/
343
251
  ├── 📦 harness/
344
252
  │ ├── constitution/ # soul.md — 11 principles
345
253
  │ ├── instructions/ # runtime + conventions
346
- │ ├── rules/ # 16 files
254
+ │ ├── rules/ # 17 files (handoff.md + 16 existing)
347
255
  │ ├── skills/ # 10 procedural skills
348
256
  │ ├── prompts/ # 25 subagent templates
349
257
  │ └── commands/ # 26 slash command templates
@@ -355,6 +263,17 @@ openhermes/
355
263
 
356
264
  ---
357
265
 
266
+ ## Environment Variables
267
+
268
+ Two knobs. That's it.
269
+
270
+ | Variable | Default | Effect |
271
+ |----------|---------|--------|
272
+ | `OPENCODE_ALLOW_PROJECT_HARNESS` | `false` | Enable project-local harness at `.opencode/openhermes/` |
273
+ | `OPENCODE_CURATOR_LOGS` | `false` | Pipe curator diagnostics to stderr for debugging |
274
+
275
+ ---
276
+
358
277
  ## Why OpenHermes ≠ Hermes Agent
359
278
 
360
279
  Same messenger emoji. Entirely different mediums.
@@ -364,10 +283,10 @@ Same messenger emoji. Entirely different mediums.
364
283
  | Platform | Standalone agent — TUI + gateway + cron | OpenCode-native plugin — lives *inside* your editor |
365
284
  | Installation | Python 3.11 + uv + 30+ deps — 5-15 min | `npm i` — 3 seconds |
366
285
  | Infrastructure | Long-running gateway, cron daemon, 20 platform adapters, 7 terminal backends, SQLite+FTS5 | Zero sidecars — everything is a plugin hook |
367
- | Memory | MEMORY.md + USER.md files + optional Honcho | 9-class schema-validated memory with in-process tools |
286
+ | Memory | MEMORY.md + USER.md files + optional Honcho | 9-class schema-validated, fingerprint-aware, in-process tools |
368
287
  | Skills | agentskills.io standard, auto-creation + self-improvement | SKILL.md progressive disclosure, auto-detected |
369
- | Context | Context files + FTS5 search + LLM summarization | Harness injection at startup, recall cache at compaction |
370
- | Philosophy | "The self-improving agent" — feature-rich, platform-expansive | "The constitutional router" — discipline-first, precision-only |
288
+ | Subagents | N/A | 25 specialists with handoff protocol, permission tiers, phase management |
289
+ | Philosophy | "The self-improving agent" — feature-rich, platform-expansive | **"The constitutional router"** — discipline-first, precision-only |
371
290
 
372
291
  Both are &#9764; messengers. Different mediums.
373
292
 
@@ -381,8 +300,8 @@ Problems, ideas, improvements? [Open an issue](https://github.com/nathwn12/openh
381
300
 
382
301
  ## License
383
302
 
384
- MIT — see [LICENSE](LICENSE).
303
+ MIT — see [LICENSE](LICENSE). All credited inspirations are independent implementations — no code copied. ECC and Hermes Agent are MIT. DCP is AGPL-3.0 but shared concepts (compress, dedup, purge) are uncopyrightable ideas (17 U.S.C. § 102(b); *Computer Assocs. v. Altai*, 982 F.2d 693). AGPL copyleft requires copying or adapting the work (§ 0) — independent implementation does not trigger it.
385
304
 
386
305
  <p align="center">
387
- <sub><b>&#9764;</b> Built with discipline. Inspired by <a href="https://github.com/NousResearch/hermes-agent">Hermes Agent</a>, <a href="https://github.com/everything-claude-code/ecc">Everything Claude Code</a>, and <a href="https://github.com/Opencode-DCP/opencode-dynamic-context-pruning">Dynamic Context Pruning</a>. Built for <a href="https://opencode.ai">OpenCode</a>.</sub>
306
+ <sub><b>&#9764;</b> Built with discipline. Inspired by <a href="https://github.com/NousResearch/hermes-agent">Hermes Agent</a> (MIT), <a href="https://github.com/affaan-m/everything-claude-code">ECC</a> (MIT), and <a href="https://github.com/Opencode-DCP/opencode-dynamic-context-pruning">DCP</a> (AGPL-3.0). Built for <a href="https://opencode.ai">OpenCode</a>.</sub>
388
307
  </p>
package/autorecall.mjs CHANGED
@@ -1,10 +1,80 @@
1
1
  import path from "node:path"
2
2
  import os from "node:os"
3
3
  import fs from "node:fs"
4
- import { atomicWriteJson, fingerprintEnvironment, isTruthy, readJson, readJsonl, sanitizeRecord, truncateText } from "./lib/hardening.mjs"
4
+ import { atomicWriteJson, buildEnvironmentFingerprint, fingerprintEnvironment, isTruthy, readJson, readJsonl, sanitizeRecord, truncateText } from "./lib/hardening.mjs"
5
5
  import { getDataRoot, getCacheRoot, getMemoryRoot, getRecallRoot, getRuntimeRoot } from "./lib/paths.mjs"
6
6
 
7
7
  const OLD_BASE = path.join(os.homedir(), ".config", "opencode", "openhermes")
8
+ const BOILERPLATE_SUMMARY = /^(Idle checkpoint for|Pre-compaction checkpoint for|Placeholder checkpoint|Session in progress|No active checkpoint)/i
9
+ const PLURALS = { audit: "audits", checkpoint: "checkpoints", mistake: "mistakes", instinct: "instincts", decision: "decisions", constraint: "constraints", backlog: "backlog", verification_receipt: "verification_receipts" }
10
+
11
+ function classDir(cls) { return path.join(getMemoryRoot(), PLURALS[cls]) }
12
+
13
+ function hasExpired(r) {
14
+ if (r?.status === "expired" || r?.status === "decayed") return true
15
+ if (r?.decay_at && Date.parse(r.decay_at) < Date.now()) return true
16
+ if (r?.expires_at && Date.parse(r.expires_at) < Date.now()) return true
17
+ return false
18
+ }
19
+
20
+ function sweepStaleRecords() {
21
+ const classes = ["checkpoints", "constraints", "decisions", "instincts", "audits", "backlog", "verification_receipts"]
22
+ let swept = 0
23
+ for (const plural of classes) {
24
+ const dir = path.join(getMemoryRoot(), plural)
25
+ let files = []
26
+ try { files = fs.readdirSync(dir).filter(f => f.endsWith(".json") && f !== "index.json") } catch { continue }
27
+ for (const f of files) {
28
+ const fp = path.join(dir, f)
29
+ const record = readJson(fp, null)
30
+ if (!record || !hasExpired(record)) continue
31
+ if (record.status === "expired" || record.status === "decayed") continue
32
+ record.status = "expired"
33
+ record.updated_at = new Date().toISOString()
34
+ atomicWriteJson(fp, record)
35
+
36
+ const indexPath = path.join(dir, "index.json")
37
+ let index = readJson(indexPath, [])
38
+ if (Array.isArray(index)) {
39
+ const idx = index.findIndex(e => e?.id === record.id)
40
+ if (idx >= 0) { index[idx].status = "expired"; index[idx].updated_at = record.updated_at }
41
+ atomicWriteJson(indexPath, index)
42
+ }
43
+ swept++
44
+ }
45
+ }
46
+ return swept
47
+ }
48
+
49
+ function sweepBoilerplateCheckpoints() {
50
+ const dir = path.join(getMemoryRoot(), "checkpoints")
51
+ let files = []
52
+ try { files = fs.readdirSync(dir).filter(f => f.endsWith(".json") && f !== "index.json") } catch { return 0 }
53
+ const cutoff = Date.now() - 86400000
54
+ let archived = 0
55
+ for (const f of files) {
56
+ const fp = path.join(dir, f)
57
+ const record = readJson(fp, null)
58
+ if (!record || record.status === "expired" || record.status === "archived") continue
59
+ if (!BOILERPLATE_SUMMARY.test(record.summary || "")) continue
60
+ const ts = Date.parse(record.updated_at || record.created_at || 0)
61
+ if (Number.isNaN(ts) || ts > cutoff) continue
62
+ record.status = "archived"
63
+ record.archived_at = new Date().toISOString()
64
+ record.updated_at = record.archived_at
65
+ atomicWriteJson(fp, record)
66
+
67
+ const indexPath = path.join(dir, "index.json")
68
+ let index = readJson(indexPath, [])
69
+ if (Array.isArray(index)) {
70
+ const idx = index.findIndex(e => e?.id === record.id)
71
+ if (idx >= 0) { index[idx].status = "archived"; index[idx].updated_at = record.updated_at }
72
+ atomicWriteJson(indexPath, index)
73
+ }
74
+ archived++
75
+ }
76
+ return archived
77
+ }
8
78
 
9
79
  function loadMemoryRecord(root, className, entry) {
10
80
  const recordPath = path.join(root, "memory", className, `${entry.id}.json`)
@@ -17,15 +87,6 @@ function loadMemoryRecord(root, className, entry) {
17
87
  }
18
88
  }
19
89
 
20
- function buildEnvironmentFingerprint(harnessRoot, directory, projectKey) {
21
- return fingerprintEnvironment({
22
- cwd: directory,
23
- harnessRoot,
24
- projectRoot: directory,
25
- project: projectKey,
26
- })
27
- }
28
-
29
90
  function formatContext(memory) {
30
91
  const parts = []
31
92
  if (memory.checkpoint) parts.push(`## Active Checkpoint\n${memory.checkpoint.summary || "N/A"}\n`)
@@ -54,7 +115,7 @@ function formatBacklogNudge(candidates) {
54
115
  `Top candidates:`,
55
116
  top,
56
117
  `Trigger: /learn to create skills from these sessions.`,
57
- `If none are skill-worthy, close them via add_memory with status:"closed".`
118
+ `If none are skill-worthy, close them via ohc_save with status:"closed".`
58
119
  ].join("\n")
59
120
  }
60
121
 
@@ -66,7 +127,13 @@ function formatMemoryWriteGap(memory) {
66
127
  return `## Memory Write Gap\nThese memory classes are empty: ${gaps.join(", ")}. Write at least one ${gaps[0]} this session.`
67
128
  }
68
129
 
130
+ export async function refreshRecallCache(projectKey, directory) {
131
+ await loadMemoryAndWriteCache(projectKey, directory)
132
+ }
133
+
69
134
  async function loadMemoryAndWriteCache(projectKey, directory) {
135
+ sweepStaleRecords()
136
+ sweepBoilerplateCheckpoints()
70
137
  const SENTINEL = path.join(getDataRoot(), ".migrated-from-v1")
71
138
  if (!fs.existsSync(SENTINEL)) {
72
139
  const oldMemory = path.join(OLD_BASE, "memory")
@@ -94,7 +161,7 @@ async function loadMemoryAndWriteCache(projectKey, directory) {
94
161
  }
95
162
 
96
163
  const memory = { constraints: [], decisions: [], mistakes: [], checkpoint: null, pendingSkillCandidates: [] }
97
- const fingerprint = buildEnvironmentFingerprint(getDataRoot(), directory, projectKey)
164
+ const fingerprint = buildEnvironmentFingerprint(getDataRoot(), directory, { name: projectKey })
98
165
 
99
166
  const constraintsIndex = readJson(path.join(getMemoryRoot(), "constraints", "index.json"), [])
100
167
  if (Array.isArray(constraintsIndex)) memory.constraints = constraintsIndex.filter(e => e.status === "active")