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.
- package/README.md +123 -208
- package/autorecall.mjs +79 -12
- package/bootstrap.mjs +122 -25
- package/curator.mjs +4 -40
- package/harness/commands/harness-audit.md +1 -1
- package/harness/commands/learn.md +2 -2
- package/harness/commands/memory-search.md +2 -2
- package/harness/constitution/soul.md +16 -4
- package/harness/instructions/RUNTIME.md +6 -3
- package/harness/prompts/architect.txt +14 -0
- package/harness/prompts/build-cpp.md +15 -1
- package/harness/prompts/build-error-resolver.md +15 -9
- package/harness/prompts/build-go.md +14 -0
- package/harness/prompts/build-java.md +15 -1
- package/harness/prompts/build-kotlin.md +15 -1
- package/harness/prompts/build-rust.md +14 -0
- package/harness/prompts/code-reviewer.md +15 -9
- package/harness/prompts/doc-updater.md +13 -0
- package/harness/prompts/docs-lookup.md +11 -0
- package/harness/prompts/e2e-runner.txt +12 -0
- package/harness/prompts/explore.md +16 -4
- package/harness/prompts/harness-optimizer.md +12 -0
- package/harness/prompts/loop-operator.md +11 -0
- package/harness/prompts/planner.md +15 -9
- package/harness/prompts/refactor-cleaner.md +14 -0
- package/harness/prompts/review-cpp.md +14 -1
- package/harness/prompts/review-database.md +13 -0
- package/harness/prompts/review-go.md +13 -0
- package/harness/prompts/review-java.md +14 -1
- package/harness/prompts/review-kotlin.md +13 -0
- package/harness/prompts/review-python.md +14 -1
- package/harness/prompts/review-rust.md +13 -0
- package/harness/prompts/security-reviewer.md +15 -9
- package/harness/prompts/tdd-guide.md +14 -0
- package/harness/rules/audit.md +2 -2
- package/harness/rules/delegation.md +0 -2
- package/harness/rules/handoff.md +267 -0
- package/harness/rules/memory-management.md +4 -4
- package/harness/rules/precedence.md +1 -1
- package/harness/rules/retrieval.md +5 -5
- package/harness/rules/runtime-guards.md +1 -1
- package/harness/rules/self-heal.md +1 -1
- package/harness/rules/session-start.md +5 -5
- package/harness/rules/skills-management.md +2 -2
- package/harness/rules/verification.md +4 -4
- package/index.mjs +6 -2
- package/lib/ambient-memory.mjs +167 -0
- package/lib/handoff.mjs +176 -0
- package/lib/hardening.mjs +13 -8
- package/lib/memory-tools-plugin.mjs +107 -54
- package/lib/ohc/block-sync.mjs +69 -0
- package/lib/ohc/compress/search.mjs +152 -0
- package/lib/ohc/compress/state.mjs +76 -0
- package/lib/ohc/config.mjs +172 -16
- package/lib/ohc/message-ids.mjs +168 -0
- package/lib/ohc/notify.mjs +150 -0
- package/lib/ohc/protected-patterns.mjs +54 -0
- package/lib/ohc/prune-apply.mjs +134 -0
- package/lib/ohc/pruner.mjs +406 -55
- package/lib/ohc/reaper.mjs +12 -3
- package/lib/ohc/state.mjs +246 -15
- package/lib/ohc/strategies/deduplication.mjs +72 -0
- package/lib/ohc/strategies/index.mjs +2 -0
- package/lib/ohc/strategies/purge-errors.mjs +43 -0
- package/lib/ohc/token-utils.mjs +26 -0
- package/lib/ohc/updater.mjs +36 -13
- package/lib/paths.mjs +0 -3
- package/lib/search.mjs +48 -0
- package/package.json +1 -1
- package/schemas/audit.schema.json +22 -1
- package/schemas/backlog.schema.json +23 -2
- package/schemas/checkpoint.schema.json +23 -2
- package/schemas/constraint.schema.json +23 -2
- package/schemas/decision.schema.json +23 -2
- package/schemas/instinct.schema.json +23 -2
- package/schemas/mistake.schema.json +23 -2
- package/schemas/verification_receipt.schema.json +23 -2
- package/skill-builder.mjs +12 -23
package/README.md
CHANGED
|
@@ -12,185 +12,102 @@
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
|
|
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
|
-
|
|
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="
|
|
35
|
-
<tr><td><b>📌
|
|
36
|
-
<tr><td><b>💾 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>&#
|
|
38
|
-
<tr><td><b>&#
|
|
39
|
-
<tr><td><b>&#
|
|
40
|
-
<tr><td><b>&#
|
|
41
|
-
<tr><td><b>🔎 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>🧩 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>🤖 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>📌 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>💾 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>🔄 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>🛠 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>🔎 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 claims — reports message count only.</td></tr>
|
|
34
|
+
<tr><td><b>🧩 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
|
-
##
|
|
39
|
+
## Agent Handoff Protocol — New in v2.5
|
|
48
40
|
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
45
|
+
**Complexity-gated routing:**
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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** | `
|
|
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
|
-
|
|
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
|
+
> **🔄 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
|
|
89
|
-
2. **Chat transform
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
132
|
+
## Self-Healing Escalation
|
|
222
133
|
|
|
223
|
-
A
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
244
|
-
|
|
150
|
+
No self-termination. No grandstanding. The agent gets better — you don't teach it twice.
|
|
151
|
+
|
|
152
|
+
---
|
|
245
153
|
|
|
246
|
-
|
|
154
|
+
## Session Lifecycle
|
|
247
155
|
|
|
248
|
-
|
|
156
|
+
Three phases. Six plugins coordinate across 20+ OpenCode hooks.
|
|
249
157
|
|
|
250
|
-
|
|
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).
|
|
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 |
|
|
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/` |
|
|
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
|
-
##
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
|
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 ☤ 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>☤</b> Built with discipline. Inspired by <a href="https://github.com/NousResearch/hermes-agent">Hermes Agent</a
|
|
302
|
+
<sub><b>☤</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
|
|
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")
|