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.
- package/README.md +125 -206
- 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,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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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="
|
|
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>
|
|
32
|
+
<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>
|
|
33
|
+
<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>
|
|
34
|
+
<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>
|
|
35
|
+
<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>
|
|
36
|
+
<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>
|
|
37
|
+
<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>
|
|
38
|
+
<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
39
|
</table>
|
|
44
40
|
|
|
45
41
|
---
|
|
46
42
|
|
|
47
|
-
##
|
|
43
|
+
## Agent Handoff Protocol — New in v2.5
|
|
48
44
|
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49
|
+
**Complexity-gated routing:**
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
70
|
+
## Setup
|
|
71
|
+
|
|
72
|
+
Add one line to your `opencode.json`:
|
|
62
73
|
|
|
63
|
-
|
|
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
|
|
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** | `
|
|
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
|
-
|
|
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
|
+
> **🔄 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
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
##
|
|
136
|
+
## Self-Healing Escalation
|
|
222
137
|
|
|
223
|
-
A
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Session Lifecycle
|
|
247
159
|
|
|
248
|
-
|
|
160
|
+
Three phases. Six plugins coordinate across 20+ OpenCode hooks.
|
|
249
161
|
|
|
250
|
-
|
|
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).
|
|
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 |
|
|
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/` |
|
|
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
|
-
##
|
|
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
|
-
|
|
313
|
-
|
|
314
|
-
|
|
|
315
|
-
|
|
316
|
-
|
|
|
317
|
-
|
|
|
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
|
|
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
|
|
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
|
-
|
|
|
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 ☤ 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>☤</b> Built with discipline. Inspired by <a href="https://github.com/NousResearch/hermes-agent">Hermes Agent</a
|
|
306
|
+
<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
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
|
|
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")
|