hmem-mcp 6.3.0 → 6.3.2
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/dist/cli-context-inject.js +8 -1
- package/dist/cli-context-inject.js.map +1 -1
- package/dist/cli-hook-startup.js +12 -9
- package/dist/cli-hook-startup.js.map +1 -1
- package/dist/cli-init.js +96 -1
- package/dist/cli-init.js.map +1 -1
- package/dist/cli-log-exchange.js +9 -4
- package/dist/cli-log-exchange.js.map +1 -1
- package/dist/hmem-config.d.ts +7 -1
- package/dist/hmem-config.js +4 -1
- package/dist/hmem-config.js.map +1 -1
- package/dist/hmem-store.d.ts +10 -31
- package/dist/hmem-store.js +22 -187
- package/dist/hmem-store.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +195 -481
- package/dist/mcp-server.js.map +1 -1
- package/opencode-plugin/hmem.js +105 -0
- package/package.json +2 -1
- package/skills/hmem-config/SKILL.md +77 -0
- package/skills/hmem-curate/SKILL.md +158 -134
- package/skills/hmem-migrate-o/SKILL.md +1 -1
- package/skills/hmem-read/SKILL.md +1 -1
- package/skills/hmem-release/SKILL.md +2 -3
- package/skills/hmem-update/SKILL.md +48 -1
- package/skills/hmem-wipe/SKILL.md +6 -4
- package/skills/hmem-write/SKILL.md +28 -5
- package/skills/hmem-self-curate/SKILL.md +0 -194
|
@@ -55,11 +55,18 @@ Check for new skills that weren't there before — inform the user about new cap
|
|
|
55
55
|
|
|
56
56
|
Hooks are critical — without them, O-entries are never logged and auto-checkpoints never fire.
|
|
57
57
|
|
|
58
|
-
Check the current hook configuration:
|
|
58
|
+
Check the current hook configuration. Use the platform-appropriate command:
|
|
59
|
+
|
|
59
60
|
```bash
|
|
61
|
+
# Linux / macOS
|
|
60
62
|
cat ~/.claude/settings.json | grep -A5 hooks
|
|
61
63
|
```
|
|
62
64
|
|
|
65
|
+
```powershell
|
|
66
|
+
# Windows (PowerShell)
|
|
67
|
+
Get-Content "$env:USERPROFILE\.claude\settings.json" | Select-String -Pattern "hooks" -Context 0,5
|
|
68
|
+
```
|
|
69
|
+
|
|
63
70
|
**Required hooks (for `checkpointMode: "auto"`):**
|
|
64
71
|
- **UserPromptSubmit** — memory load + checkpoint reminder
|
|
65
72
|
- **Stop** — exchange logging (`hmem log-exchange`) + O-entry title generation
|
|
@@ -73,6 +80,46 @@ cat ~/.claude/settings.json | grep -A5 hooks
|
|
|
73
80
|
- Check that hook scripts exist and are executable
|
|
74
81
|
- Verify they reference the current hmem installation path
|
|
75
82
|
|
|
83
|
+
### Windows-specific hook checks (CRITICAL)
|
|
84
|
+
|
|
85
|
+
On Windows, two specific issues break hooks. Always run these checks when updating on Windows:
|
|
86
|
+
|
|
87
|
+
**Check 1 — `shell: powershell` present on every hook command?**
|
|
88
|
+
|
|
89
|
+
Each object in `hooks.*.hooks` and the `statusLine` object must contain `"shell": "powershell"`. Without it, Claude Code may route the command through Git Bash, whose MSYS2 runtime crashes transiently at startup (`bash.exe: *** fatal error - add_item ... errno 1`) before the command is even parsed. Every hook then fails with a generic error.
|
|
90
|
+
|
|
91
|
+
**Check 2 — No inline env-var syntax in commands?**
|
|
92
|
+
|
|
93
|
+
Commands must NOT contain `VAR=value` prefixes like `HMEM_PATH=C:/... node ...`. That's bash-only syntax; cmd.exe and PowerShell interpret `HMEM_PATH=...` as the command name and fail. All env vars must live in the top-level `env` block of settings.json.
|
|
94
|
+
|
|
95
|
+
**The correct Windows shape:**
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"env": {
|
|
100
|
+
"HMEM_PATH": "C:/Users/<you>/.hmem/Agents/<AGENT>/<AGENT>.hmem"
|
|
101
|
+
},
|
|
102
|
+
"hooks": {
|
|
103
|
+
"Stop": [
|
|
104
|
+
{
|
|
105
|
+
"matcher": "",
|
|
106
|
+
"hooks": [
|
|
107
|
+
{
|
|
108
|
+
"type": "command",
|
|
109
|
+
"command": "node C:/Users/<you>/AppData/Roaming/npm/node_modules/hmem-mcp/dist/cli.js log-exchange",
|
|
110
|
+
"shell": "powershell"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**If either check fails:** Offer to fix settings.json automatically. The fix is lossless on other platforms, so it's safe to apply even on shared configs synced across OSes. Point the user to the Windows hook section in `/hmem-config` for the full pattern (UserPromptSubmit, Stop, SessionStart, statusLine).
|
|
120
|
+
|
|
121
|
+
**After fixing:** Claude Code must be restarted so the `env` block is re-loaded and hooks are re-registered with the new shell.
|
|
122
|
+
|
|
76
123
|
---
|
|
77
124
|
|
|
78
125
|
## Step 2c: Check load_project Display Config
|
|
@@ -76,15 +76,17 @@ Do NOT attempt to run /clear yourself — it is a built-in CLI command only the
|
|
|
76
76
|
|
|
77
77
|
## What happens after /clear
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
Context is restored **automatically** by the `SessionStart[clear]` hook — no
|
|
80
|
+
agent action needed after /clear. Do **NOT** call `load_project` or `read_memory`
|
|
81
|
+
during or after this skill; the next session's first UserPromptSubmit hook will
|
|
82
|
+
trigger the normal hmem-read flow with a verified active project ID.
|
|
83
|
+
|
|
84
|
+
The hook:
|
|
80
85
|
1. Resets the MCP session cache
|
|
81
86
|
2. Injects recent conversation exchanges from the project's O-entry transcript
|
|
82
87
|
3. Injects the active project briefing (overview expanded)
|
|
83
88
|
4. Injects recent O-entry titles + rules
|
|
84
89
|
|
|
85
|
-
The agent then calls `load_project` and has full context to continue working.
|
|
86
|
-
No manual restoration needed.
|
|
87
|
-
|
|
88
90
|
## Why this flow works
|
|
89
91
|
|
|
90
92
|
- **O-entries are covered.** The Stop hook logs every exchange to the active
|
|
@@ -131,10 +131,20 @@ append_memory(id="P0048.6", content="Auto-sync fails with multiple .hmem in CWD
|
|
|
131
131
|
```
|
|
132
132
|
Custom prefixes are merged with the defaults — they don't replace them. Without registering, the system will reject the prefix.
|
|
133
133
|
|
|
134
|
-
###
|
|
134
|
+
### Schema-Enforced Entries (P and any prefix with a defined schema)
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
The MCP server enforces schemas for any prefix that has a `schemas` entry in `hmem.config.json`.
|
|
137
|
+
For those prefixes, two rules apply:
|
|
138
|
+
|
|
139
|
+
1. **`write_memory`**: L2 node names must match the defined section names (error otherwise).
|
|
140
|
+
2. **`append_memory` to root entry (e.g. `P0029`, no dot)**: **blocked** — you cannot add new L2 sections.
|
|
141
|
+
You must append to a specific section: `append_memory(id="P0029.N", content="...")`.
|
|
142
|
+
|
|
143
|
+
By default, `P` has a schema. If `L`, `D`, or other prefixes are configured with schemas, the same rules apply.
|
|
144
|
+
|
|
145
|
+
### P-Entry Standard Schema
|
|
146
|
+
|
|
147
|
+
Every project entry MUST follow this structure.
|
|
138
148
|
|
|
139
149
|
**L1 Title:** `Name | Status | Tech Stack | GH: owner/repo | Short description`
|
|
140
150
|
The GH field is optional — include it when a GitHub repo exists, omit otherwise.
|
|
@@ -327,7 +337,8 @@ read_memory(id="P0029") # shows root + all L2 titles
|
|
|
327
337
|
```
|
|
328
338
|
Do any L2 titles match the sub-topic?
|
|
329
339
|
|
|
330
|
-
- **No match** → `append_memory(id="P0029", content="...")` adds a new L2
|
|
340
|
+
- **No match (and no schema)** → `append_memory(id="P0029", content="...")` adds a new L2
|
|
341
|
+
- **No match (schema-constrained entry like P)** → find the closest existing section and append there (L2 additions are blocked)
|
|
331
342
|
- **Match found (e.g. .15)** → continue to Step 3
|
|
332
343
|
|
|
333
344
|
**Step 3 — Drill into that L2**
|
|
@@ -411,12 +422,24 @@ Appends new child nodes under an existing root or node. Existing children are pr
|
|
|
411
422
|
Content indentation is **relative to the parent** — 0 tabs = direct child of `id`.
|
|
412
423
|
Body works the same as in `write_memory` — blank line separates title from body.
|
|
413
424
|
|
|
425
|
+
> **Schema enforcement:** For entries with a defined schema (e.g., all P-entries), appending
|
|
426
|
+
> to the root (e.g., `id="P0029"`) is **blocked** — that would create a new L2 section outside
|
|
427
|
+
> the schema. You must target a specific section: `append_memory(id="P0029.3", content="...")`.
|
|
428
|
+
> For entries without a schema (L, D, E, etc. by default), root appends are allowed.
|
|
429
|
+
|
|
414
430
|
```
|
|
415
431
|
append_memory(
|
|
416
432
|
id="L0003",
|
|
417
433
|
content="New finding discovered later\n\nDetailed explanation of what was found and why it matters.\nThis can span multiple lines.\n\tSub-detail about it"
|
|
418
434
|
)
|
|
419
435
|
# → adds L0003.N (L2 with title + body) and L0003.N.1 (L3)
|
|
436
|
+
# ↑ only works if L has no schema defined; use L0003.N for schema-constrained entries
|
|
437
|
+
|
|
438
|
+
append_memory(
|
|
439
|
+
id="P0029.3",
|
|
440
|
+
content="New detail in the Usage section"
|
|
441
|
+
)
|
|
442
|
+
# → adds P0029.3.M (L3 under section .3) — correct way for schema-constrained entries
|
|
420
443
|
|
|
421
444
|
append_memory(
|
|
422
445
|
id="L0003.2",
|
|
@@ -434,7 +457,7 @@ Use when: you have new context to add without replacing what's there.
|
|
|
434
457
|
| L1 wording is wrong/outdated | `update_memory` |
|
|
435
458
|
| A sub-node has wrong detail | `update_memory` |
|
|
436
459
|
| You have new info to add | `append_memory` |
|
|
437
|
-
| Entry is completely wrong |
|
|
460
|
+
| Entry is completely wrong | mark obsolete with `[✓newId]`, then `write_memory` for the correction |
|
|
438
461
|
|
|
439
462
|
---
|
|
440
463
|
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: hmem-self-curate
|
|
3
|
-
description: Curate your own memory. Systematically review entries — mark obsolete, irrelevant, or favorite. Run periodically to keep memory clean. Use when asked to "aufräumen", "clean up memory", "alte Einträge prüfen", "memory review", "Speicher bereinigen", "curate", "tidy up", or when memory_health() shows issues.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Self-Curation: Review Your Own Memory
|
|
7
|
-
|
|
8
|
-
You are curating **your own** memory. You know best which entries are still relevant.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Step 0: Health Check First
|
|
13
|
-
|
|
14
|
-
Before diving in, run an audit to get a prioritized list of issues:
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
memory_health()
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
This instantly shows:
|
|
21
|
-
- **Broken links** — fix or remove them first (high impact, easy to miss manually)
|
|
22
|
-
- **Orphaned entries** — root entries with no sub-nodes (likely draft stubs)
|
|
23
|
-
- **Stale favorites/pinned** — favorites not accessed in >60 days (demote or verify)
|
|
24
|
-
- **Broken obsolete chains** — `[✓ID]` pointing to deleted entries
|
|
25
|
-
|
|
26
|
-
Also useful before starting:
|
|
27
|
-
```
|
|
28
|
-
memory_stats() # overview: how many entries per prefix, stale count, etc.
|
|
29
|
-
read_memory(stale_days=60) # entries not touched in 60 days — prime curation candidates
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## Workflow: Prefix by Prefix
|
|
35
|
-
|
|
36
|
-
Work through one prefix at a time. Load all entries of a prefix with full depth:
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
read_memory(prefix="P", show_all=true)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
This bypasses the bulk-read algorithm and session cache — every entry is expanded with L2+L3 children visible. Review each entry in the output directly — no need to drill into individual entries.
|
|
43
|
-
|
|
44
|
-
**Order:** Start with the prefix that has the most entries (usually P), then move to L, E, D, O, etc.
|
|
45
|
-
|
|
46
|
-
If context overflows mid-prefix, continue with the remaining entries — your memory survives compression.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## O-Entries (Session Logs)
|
|
51
|
-
|
|
52
|
-
O-entries accumulate automatically via the Stop hook — each session creates one per project. `load_project` injects the latest session's **checkpoint summary** (if available) plus the most recent raw exchanges.
|
|
53
|
-
|
|
54
|
-
**Checkpoint summaries:** Auto-checkpoints write a `[CP]` prefixed summary node (tagged `#checkpoint-summary`) under the O-entry. These rolling summaries compress older exchanges so `load_project` stays compact. Older summaries are further compressed into 1-2 sentences by each new checkpoint.
|
|
55
|
-
|
|
56
|
-
**Skill-dialog filtering:** Exchanges containing skill activations (brainstorming, TDD, debugging) are tagged `#skill-dialog` at the exchange-node level and automatically excluded from `load_project` / `/clear` output. The full content remains accessible via `read_memory(id="O0123")`.
|
|
57
|
-
|
|
58
|
-
**Curation rules for O-entries:**
|
|
59
|
-
- **Leave them alone.** Old O-entries don't cause harm — they're excluded from bulk reads and `load_project` only shows the most recent one.
|
|
60
|
-
- **Don't mark them irrelevant or obsolete** — they serve as historical record and can be useful for checkpoint agents extracting L/D/E.
|
|
61
|
-
- **Skip O-entries during curation.** Focus your time on L, E, D, P entries where curation has real impact.
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## Bulk Operations
|
|
66
|
-
|
|
67
|
-
For large-scale curation across many entries, use the bulk tools instead of updating one by one:
|
|
68
|
-
|
|
69
|
-
| Tool | Purpose |
|
|
70
|
-
|------|---------|
|
|
71
|
-
| `update_many(updates=[...])` | Batch-update multiple entries at once (content, flags, etc.) |
|
|
72
|
-
| `tag_bulk(ids=[...], add_tags=[...], remove_tags=[...])` | Add or remove tags across many entries in one call |
|
|
73
|
-
| `tag_rename(old_tag="...", new_tag="...")` | Rename a tag globally across all entries |
|
|
74
|
-
|
|
75
|
-
These are especially useful when a curation pass reveals a pattern (e.g., 10 entries that all need the same tag added, or a batch of stale entries to mark irrelevant).
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Title Quality Check
|
|
80
|
-
|
|
81
|
-
Since v5.1, every node has a **title** (short navigation label, ~50 chars) and an optional **body** (detailed content shown on drill-down). During curation, check whether titles are good navigation labels:
|
|
82
|
-
|
|
83
|
-
- **Vague title?** Update it: `update_memory(id="L0003", content="Better, specific title")`
|
|
84
|
-
- **Title = full content?** Old entries without body separation have `title = autoExtract(content)`. If the content is valuable but the title is truncated gibberish, rewrite with explicit title + blank line + body.
|
|
85
|
-
- **Long content in a leaf node?** Consider whether it would benefit from title/body separation: `update_memory(id, content="Clear title\n\nDetailed body text")`.
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## For Each Entry: Decide and Act
|
|
90
|
-
|
|
91
|
-
| Decision | Action |
|
|
92
|
-
|----------|--------|
|
|
93
|
-
| Still valid and useful | Skip (no action needed) |
|
|
94
|
-
| Important reference I need every session | `update_memory(id="X", content="...", favorite=true)` |
|
|
95
|
-
| Outdated — a better entry exists | Mark obsolete (see below) |
|
|
96
|
-
| Just noise — not wrong, but irrelevant | `update_memory(id="X", content="...", irrelevant=true)` |
|
|
97
|
-
| Title is vague or misleading | `update_memory(id="X", content="Better wording")` |
|
|
98
|
-
| Sub-node has valuable reference info | `update_memory(id="X.N", content="...", favorite=true)` |
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## Marking Obsolete
|
|
103
|
-
|
|
104
|
-
Obsolete requires a correction reference. Three patterns:
|
|
105
|
-
|
|
106
|
-
**A: Replacement exists already**
|
|
107
|
-
```
|
|
108
|
-
update_memory(id="E0023", content="Wrong approach — see [✓E0076]", obsolete=true)
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**B: No replacement exists yet**
|
|
112
|
-
```
|
|
113
|
-
write_memory(prefix="L", content="Correct approach is XYZ\n\tDetails...") # -> L0090
|
|
114
|
-
update_memory(id="L0042", content="Superseded — see [✓L0090]", obsolete=true)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**C: Just stale, no correction needed**
|
|
118
|
-
If the entry is simply outdated with no replacement (e.g., a finished task, a past state):
|
|
119
|
-
```
|
|
120
|
-
update_memory(id="T0005", content="...", irrelevant=true)
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## Consolidate Duplicates
|
|
126
|
-
|
|
127
|
-
Look for entries covering the same topic (common with P entries). Merge them:
|
|
128
|
-
|
|
129
|
-
1. Pick the **keeper** (the more complete one)
|
|
130
|
-
2. Copy unique info from the duplicate: `append_memory(id="P0029", content="Session from duplicate\n\tDetail carried over")`
|
|
131
|
-
3. Mark the duplicate obsolete with a correction reference: `update_memory(id="P0031", content="Merged into [✓P0029]", obsolete=true)`
|
|
132
|
-
|
|
133
|
-
**Note:** Only curators (ceo role) can delete entries via `delete_agent_memory`. As a worker agent, use `obsolete=true` with `[✓ID]` to point to the keeper. Obsolete entries are hidden from bulk reads and won't cause confusion.
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## Relocate Misplaced Nodes
|
|
138
|
-
|
|
139
|
-
When a sub-node belongs under a different root or parent, use `move_memory` to cut and re-insert it. All IDs, links, and `[✓ID]` content references are updated automatically.
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
# Move P0029.15 to become a child of L0074
|
|
143
|
-
move_memory(source_id="P0029.15", target_parent_id="L0074")
|
|
144
|
-
# → P0029.15 (+ all children) become L0074.N (new seq under L0074)
|
|
145
|
-
|
|
146
|
-
# Move within the same root: P0029.15 → under P0029.20
|
|
147
|
-
move_memory(source_id="P0029.15", target_parent_id="P0029.20")
|
|
148
|
-
# → becomes P0029.20.N with all children re-keyed
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
**Constraints:**
|
|
152
|
-
- `source_id` must be a sub-node — cannot move root entries
|
|
153
|
-
- Cannot move a node into its own subtree
|
|
154
|
-
- Curator variant: `move_agent_memory(agent_name="THOR", source_id="...", target_parent_id="...")`
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Favorite Audit
|
|
159
|
-
|
|
160
|
-
Check `[♥]` markers in the output.
|
|
161
|
-
|
|
162
|
-
- **Too many?** If >10% are favorites, demote less important ones: `update_memory(id="X", content="...", favorite=false)`
|
|
163
|
-
- **Missing?** Reference entries you always need (API endpoints, key decisions, patterns) should be favorited.
|
|
164
|
-
- **Sub-nodes:** If a specific L2/L3 is the real reference, favorite the sub-node instead.
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
## Guidelines
|
|
169
|
-
|
|
170
|
-
- **One prefix per batch.** Don't try all 200+ entries at once — focus on one prefix per `show_all` call.
|
|
171
|
-
- **Preserve learning value.** Error entries (E) and lessons (L) about *why* something failed are valuable even if the bug is fixed. Only mark obsolete if the analysis is wrong.
|
|
172
|
-
- **When in doubt, skip.** False irrelevant/obsolete is harder to undo than leaving an entry alone.
|
|
173
|
-
- **Update stale L1 text.** A clear L1 is the most impactful improvement you can make.
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
## Quick Reference
|
|
178
|
-
|
|
179
|
-
| Tool | When |
|
|
180
|
-
|------|------|
|
|
181
|
-
| `memory_health()` | **Start here** — broken links, orphans, stale favorites |
|
|
182
|
-
| `memory_stats()` | Overview before starting |
|
|
183
|
-
| `read_memory(stale_days=60)` | Prime curation targets |
|
|
184
|
-
| `read_memory(prefix="X", show_all=true)` | Load entire prefix for review |
|
|
185
|
-
| `update_memory(id, content, favorite=true)` | Mark as always-show reference |
|
|
186
|
-
| `update_memory(id, content, irrelevant=true)` | Hide from bulk reads (noise) |
|
|
187
|
-
| `update_memory(id, content, obsolete=true)` | Mark as wrong (needs [✓ID]) |
|
|
188
|
-
| `append_memory(id, content)` | Merge info into keeper |
|
|
189
|
-
| `move_memory(source_id, target_parent_id)` | Relocate misplaced sub-node (updates all refs) |
|
|
190
|
-
| `update_memory(id, content="Merged into [✓X]", obsolete=true)` | Mark duplicate as obsolete (point to keeper) |
|
|
191
|
-
| `update_many(updates=[...])` | Batch-update multiple entries at once |
|
|
192
|
-
| `tag_bulk(ids=[...], add_tags, remove_tags)` | Add/remove tags across many entries |
|
|
193
|
-
| `tag_rename(old_tag, new_tag)` | Rename a tag globally |
|
|
194
|
-
| `read_memory(show_obsolete=true, prefix="X")` | Review already-obsolete entries |
|