openhermes 1.13.1 → 2.5.1

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 +123 -208
  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,102 @@
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
- ```bash
18
- npm i openhermes
15
+ ```json
16
+ { "plugin": ["openhermes"] }
19
17
  ```
20
18
 
21
- ---
19
+ **One line. 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
+ No Python. No Docker. No cron. No database. Just Node.js and your existing OpenCode runtime.
28
22
 
29
23
  ---
30
24
 
31
25
  ## What OpenHermes Does For Your Agent
32
26
 
33
27
  <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>
28
+ <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>
29
+ <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>
30
+ <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>
31
+ <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>
32
+ <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>
33
+ <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>
34
+ <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
35
  </table>
44
36
 
45
37
  ---
46
38
 
47
- ## Setup
39
+ ## Agent Handoff Protocol — New in v2.5
48
40
 
49
- Add one line to your `opencode.json`. Two good options:
41
+ 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
42
 
51
- ### Published Release
43
+ **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
44
 
53
- Use npm when you want a stable release boundary.
45
+ **Complexity-gated routing:**
54
46
 
55
- ```json
56
- {
57
- "plugin": ["openhermes"]
58
- }
59
- ```
47
+ | Level | Criteria | Strategy |
48
+ |-------|----------|----------|
49
+ | **Easy** | 1-2 files, well-known pattern, single change | Handle directly |
50
+ | **Medium** | 3-10 files, new feature, needs exploration | 2-5 subagents, sequential or fan-out |
51
+ | **Hard** | 10+ files, cross-cutting change | Sequential: planner → executor → reviewers |
52
+ | **Very Large** | 50+ files, massive refactor | Fan-out: split into chunks, parallel, consolidate |
53
+
54
+ **Permission tiers:**
60
55
 
61
- ### Git-Backed
56
+ | Tier | Agents | Can edit? | Can exec? | Can review? |
57
+ |------|--------|-----------|-----------|-------------|
58
+ | 1 | planners, architects, reviewers, explore | ❌ | ❌ | ✅ |
59
+ | 2 | builders, doc-updaters, refactor-cleaners | ✅ | ✅ | ❌ (own work) |
60
+ | 3 | primary agent, loop-operator, e2e-runner | ✅ | ✅ | ✅ |
62
61
 
63
- Use GitHub when you want the latest pushed changes immediately.
62
+ **Built library** `lib/handoff.mjs` (136 lines, 5 exports): `handoffRequest`, `parseHandoffResult`, `assessComplexity`, `suggestAgent`, `canAgent`. Simple enough to audit. Sophisticated enough to govern 25 agents.
64
63
 
64
+ ---
65
+
66
+ ## Setup
67
+
68
+ Add one line to your `opencode.json`:
69
+
70
+ ### Published Release (stable)
65
71
  ```json
66
- {
67
- "plugin": ["openhermes@git+https://github.com/nathwn12/openhermes.git"]
68
- }
72
+ { "plugin": ["openhermes"] }
73
+ ```
74
+
75
+ ### Git-Backed (latest pushed changes)
76
+ ```json
77
+ { "plugin": ["openhermes@git+https://github.com/nathwn12/openhermes.git"] }
69
78
  ```
70
79
 
71
80
  Either way, **no other config needed.** The plugin auto-registers:
72
81
 
73
82
  | What | Details |
74
83
  |------|---------|
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 |
84
+ | **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
85
  | **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 |
86
+ | **6 native memory tools** | `ohc_save`, `ohc_get`, `ohc_list`, `ohc_latest`, `ohc_search`, `ohc_archive` — in-process, no MCP server |
78
87
  | **10 procedural skills** | API design, backend patterns, coding standards, E2E testing, frontend patterns, frontend slides, security review, strategic compaction, TDD workflow, verification loop |
79
88
  | **6 lifecycle plugins** | bootstrap, curator, autorecall, skill-builder, memory-tools, ohc |
80
89
 
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.
90
+ > **&#128260; Force update:** Run `/update-me` anytime to clear stale cache and reload from source. Works with both git-backed and npm installs.
84
91
 
85
92
  <details>
86
93
  <summary><b>What happens on your next session</b></summary>
87
94
 
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.
95
+ 1. **Config hook** — BootstrapPlugin registers 25 subagents, 28 commands, 10 skill paths
96
+ 2. **Chat transform** — Constitution + Runtime + Router injected into first user message
97
+ 3. **Session created** — AutorecallPlugin builds recall cache from prior session memory
98
+ 4. **Tools execute** — SkillBuilderPlugin watches calls; MemoryToolsPlugin provides 6 native tools immediately
99
+ 5. **Session idle** — CuratorPlugin snapshots checkpoint + verification receipt
100
+ 6. **Session error** — CuratorPlugin logs mistake with root cause + prevention rule
101
+ 7. **Compaction** — CuratorPlugin force-writes pre-compaction checkpoint and injects state into compaction buffer
100
102
 
103
+ No polling. No cron. Six plugins, 20+ hooks, one runtime.
101
104
  </details>
102
105
 
103
106
  ---
104
107
 
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
108
  ## Memory Architecture
190
109
 
191
- Nine schema-validated classes across two dimensions what the record is and where it lives.
192
-
193
- ### Classes
110
+ Nine schema-validated classes. All scrubbed of proto-poison, secrets, and overflow before hitting disk.
194
111
 
195
112
  | Class | Format | Layer | Purpose |
196
113
  |-------|--------|-------|---------|
@@ -204,50 +121,58 @@ Nine schema-validated classes across two dimensions — what the record is and w
204
121
  | `verification_receipt` | JSON | ✅ Integrity | Cached verification results keyed by artifact fingerprint |
205
122
  | `recall` | JSON | ✅ Integrity | Session-start cache for compaction buffer injection |
206
123
 
207
- ### Storage
124
+ **Storage:** `~/.local/share/opencode/openhermes/` for durable memory, `~/.cache/opencode/openhermes/recall/` for derived cache, `~/.config/opencode/ohc.json` for pruner config.
208
125
 
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/` |
126
+ **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.
214
127
 
215
- ### Hardening
216
-
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.
128
+ **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
129
 
219
130
  ---
220
131
 
221
- ## Session Lifecycle
132
+ ## Self-Healing Escalation
222
133
 
223
- A session runs through three phases. Six plugins coordinate across 20+ OpenCode hooks no polling, no cron, no sidecars.
134
+ A mistake is not a failure it's a signal. OpenHermes escalates through four tiers before it ever reaches you.
224
135
 
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
136
  ```
137
+ T0 ── Any mistake
138
+ Observe → log mistake record → smallest safe correction → verify
232
139
 
233
- **⚙️ Execution per tool call, per subagent spawn**
234
- ```
235
- tool.execute.* SkillBuilderPlugin counts calls + spawns
236
- ```
140
+ T1 ── Same mistake repeats within 7 days
141
+ Add prevention rule → targeted verification
237
142
 
238
- **⏹️ Cooldown auto-triggered by OpenCode lifecycle**
143
+ T2 ── Prevention failed / systemic issue
144
+ Delegate to specialist → deep audit → backlog item → structural fix
145
+
146
+ T3 ── Cascading failures
147
+ Constrained safe mode: narrow claims, preserve receipts, produce handoff
239
148
  ```
240
- session.idle CuratorPlugin: checkpoint snapshot + verification receipt
241
- SkillBuilderPlugin: complexity check → backlog candidate
242
149
 
243
- session.compacting CuratorPlugin: force-writes pre-compaction checkpoint
244
- Injects harness state + recall context → compaction buffer
150
+ No self-termination. No grandstanding. The agent gets better — you don't teach it twice.
151
+
152
+ ---
245
153
 
246
- session.compacted CuratorPlugin: updates loop-state to "compacted"
154
+ ## Session Lifecycle
247
155
 
248
- session.error CuratorPlugin: logs mistake (type, root cause, fix, prevention)
156
+ Three phases. Six plugins coordinate across 20+ OpenCode hooks.
249
157
 
250
- permission.replied CuratorPlugin: writes audit record for every permission decision
158
+ ```
159
+ ▶️ Warmup
160
+ config hook BootstrapPlugin registers harness/skills/, skills auto-discover
161
+ session.created BootstrapPlugin injects constitution → router → runtime
162
+ AutorecallPlugin loads disk memory → writes recall cache
163
+ SkillBuilderPlugin resets counters
164
+
165
+ ⚙️ Execution
166
+ tool.execute.* SkillBuilderPlugin counts calls + spawns
167
+
168
+ ⏹️ Cooldown
169
+ session.idle CuratorPlugin: checkpoint snapshot + verification receipt
170
+ SkillBuilderPlugin: complexity check → backlog candidate
171
+ session.compacting CuratorPlugin: force-writes pre-compaction checkpoint
172
+ Injects harness state + recall context → compaction buffer
173
+ session.compacted CuratorPlugin: updates loop-state to "compacted"
174
+ session.error CuratorPlugin: logs mistake (type, root cause, fix, prevention)
175
+ permission.replied CuratorPlugin: writes audit record for every permission decision
251
176
  ```
252
177
 
253
178
  ---
@@ -264,7 +189,7 @@ One core habit — **verify before claiming success.**
264
189
  | 🔄 Re-verify on change | Stale receipt is worse than no receipt |
265
190
  | 🚩 Flag contradictions | Silence is consent to bugs |
266
191
 
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."
192
+ 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
193
 
269
194
  ---
270
195
 
@@ -272,11 +197,11 @@ Verification receipts are a first-class memory type — keyed by artifact identi
272
197
 
273
198
  The full operational doctrine ships inside the package. Six directories, zero dependencies outside Node.js.
274
199
 
275
- | Directory | What it contains | Why it matters |
276
- |-----------|-----------------|----------------|
200
+ | Directory | Contents | Purpose |
201
+ |-----------|----------|---------|
277
202
  | `constitution/` | `soul.md` — 11 immutable principles | Your agent's personality, frozen |
278
203
  | `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 |
204
+ | `rules/` | 17 files: retrieval, verification, audit, self-heal, delegation, handoff | The legal framework — no ambiguity |
280
205
  | `skills/` | 10 procedural SKILL.md files | Domain expertise discovered automatically |
281
206
  | `prompts/` | 25 subagent prompt templates | Language specialists, docs lookup, loop drivers — all on tap |
282
207
  | `commands/` | 26 slash command templates | From `/verify` to `/review-go` — full toolbelt |
@@ -285,42 +210,20 @@ OpenHermes is not a runtime shim. The doctrine ships with the package — every
285
210
 
286
211
  ---
287
212
 
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
213
+ ## The Six Plugins
295
214
 
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
311
-
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 |
215
+ | Plugin | Hook Points | Job |
216
+ |--------|-------------|-----|
217
+ | **Bootstrap** | `config`, `chat.transform` | Registers agents/commands/skills; injects constitution + router + runtime |
218
+ | **MemoryTools** | (tool registration) | Provides 6 `ohc_*` tools — no MCP server, no network |
219
+ | **Curator** | `session.idle`, `.error`, `.compacted`, `.compacting`, `permission.replied` | Snapshots state, logs mistakes, records decisions, injects into compaction |
220
+ | **Autorecall** | `session.created` | Loads prior session memory into recall cache at startup |
221
+ | **SkillBuilder** | `session.created`, `.idle`, `tool.execute.after` | Auto-detects complex sessions (8+ calls or 2+ spawns) → backlog candidates |
222
+ | **OhcPlugin** | `config`, all transform/command hooks | Silent context pruner; injects budget; progressive nudges; `/ohc` command + `compress` tool |
318
223
 
319
224
  ---
320
225
 
321
- ## Architecture
322
-
323
- Three layers. All ES modules. One runtime dependency.
226
+ ## Architecture — Three Layers, One Dependency
324
227
 
325
228
  ```
326
229
  openhermes/
@@ -333,6 +236,7 @@ openhermes/
333
236
 
334
237
  ├── ⚡ lib/
335
238
  │ ├── memory-tools-plugin.mjs # 5 hm_* tools
239
+ │ ├── handoff.mjs # Structured delegation protocol
336
240
  │ ├── hardening.mjs # sanitize, redact, atomic write
337
241
  │ ├── paths.mjs # storage root resolver
338
242
  │ ├── schema-validator.mjs # Draft-07 validation
@@ -343,7 +247,7 @@ openhermes/
343
247
  ├── 📦 harness/
344
248
  │ ├── constitution/ # soul.md — 11 principles
345
249
  │ ├── instructions/ # runtime + conventions
346
- │ ├── rules/ # 16 files
250
+ │ ├── rules/ # 17 files (handoff.md + 16 existing)
347
251
  │ ├── skills/ # 10 procedural skills
348
252
  │ ├── prompts/ # 25 subagent templates
349
253
  │ └── commands/ # 26 slash command templates
@@ -355,6 +259,17 @@ openhermes/
355
259
 
356
260
  ---
357
261
 
262
+ ## Environment Variables
263
+
264
+ Two knobs. That's it.
265
+
266
+ | Variable | Default | Effect |
267
+ |----------|---------|--------|
268
+ | `OPENCODE_ALLOW_PROJECT_HARNESS` | `false` | Enable project-local harness at `.opencode/openhermes/` |
269
+ | `OPENCODE_CURATOR_LOGS` | `false` | Pipe curator diagnostics to stderr for debugging |
270
+
271
+ ---
272
+
358
273
  ## Why OpenHermes ≠ Hermes Agent
359
274
 
360
275
  Same messenger emoji. Entirely different mediums.
@@ -364,10 +279,10 @@ Same messenger emoji. Entirely different mediums.
364
279
  | Platform | Standalone agent — TUI + gateway + cron | OpenCode-native plugin — lives *inside* your editor |
365
280
  | Installation | Python 3.11 + uv + 30+ deps — 5-15 min | `npm i` — 3 seconds |
366
281
  | 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 |
282
+ | Memory | MEMORY.md + USER.md files + optional Honcho | 9-class schema-validated, fingerprint-aware, in-process tools |
368
283
  | 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 |
284
+ | Subagents | N/A | 25 specialists with handoff protocol, permission tiers, phase management |
285
+ | Philosophy | "The self-improving agent" — feature-rich, platform-expansive | **"The constitutional router"** — discipline-first, precision-only |
371
286
 
372
287
  Both are &#9764; messengers. Different mediums.
373
288
 
@@ -381,8 +296,8 @@ Problems, ideas, improvements? [Open an issue](https://github.com/nathwn12/openh
381
296
 
382
297
  ## License
383
298
 
384
- MIT — see [LICENSE](LICENSE).
299
+ 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
300
 
386
301
  <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>
302
+ <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
303
  </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")