Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fb8ee0d
feat(config): add memory feature configuration keys
TheOrdinaryWow May 13, 2026
b5e8a37
feat(shared): add withTimeout utility
TheOrdinaryWow May 13, 2026
af54cf2
feat(shared): add generic dedupe helper
TheOrdinaryWow May 13, 2026
d0dc9f4
refactor(shared): consolidate ID generation
TheOrdinaryWow May 13, 2026
0d7f6e5
feat(memory): strip inbound metadata from queries
TheOrdinaryWow May 13, 2026
303c57d
feat(memory): format timestamps as relative time
TheOrdinaryWow May 13, 2026
ca31010
feat(memory): add entity context guidance
TheOrdinaryWow May 13, 2026
6863229
chore: remove internal identifiers from comments and test labels
TheOrdinaryWow May 13, 2026
8fc208b
docs(config): correct loader docstring for two-tier lookup
TheOrdinaryWow May 13, 2026
42ac254
feat(memory): dedupe memories by content hash
TheOrdinaryWow May 13, 2026
3135fe2
feat(signal): heuristic signal extraction pipeline
TheOrdinaryWow May 13, 2026
6d6c71d
feat(capture): persistent per-session capture tracker
TheOrdinaryWow May 13, 2026
2dbac57
feat(memory): auto-categorize stored memories
TheOrdinaryWow May 13, 2026
f141f0b
feat(memory): show memory usage footer
TheOrdinaryWow May 13, 2026
bb03e0e
feat(memory): wrap client calls with timeout and dedupe
TheOrdinaryWow May 13, 2026
68bcc52
feat(memory): dedupe profile facts across sources
TheOrdinaryWow May 13, 2026
e368ed6
feat(capture): incremental capture on assistant finish
TheOrdinaryWow May 13, 2026
3c35e3b
feat(capture): save summary on session end
TheOrdinaryWow May 13, 2026
c2353ea
feat(recall): query memories on every message
TheOrdinaryWow May 13, 2026
450a305
feat(recall): re-inject context on a configurable cadence
TheOrdinaryWow May 13, 2026
b11da76
feat(compaction): full save before summarization
TheOrdinaryWow May 13, 2026
2c54e6f
feat(compaction): rehydrate context after summarization
TheOrdinaryWow May 13, 2026
4ada1e3
feat(plugin): wire memory feature hooks into entry point
TheOrdinaryWow May 13, 2026
7abd380
chore(config): regenerate JSON schema
TheOrdinaryWow May 13, 2026
dbc6ba9
test(contract): cover new plugin hooks
TheOrdinaryWow May 13, 2026
517c5c6
style: apply biome formatting fixes
TheOrdinaryWow May 13, 2026
ea8647a
fix: eliminate biome warnings in signal and test files
TheOrdinaryWow May 13, 2026
5bea18c
docs: document memory feature suite
TheOrdinaryWow May 13, 2026
eb0811c
fix: extract user prompt before persisting and re-injecting memory
TheOrdinaryWow May 13, 2026
b4c1ba8
chore: add purge script for legacy injected memories
TheOrdinaryWow May 13, 2026
10c5bbe
test: cover regression where injected markers force agent switch
TheOrdinaryWow May 13, 2026
0e1f221
docs: note injection filtering and purge script
TheOrdinaryWow May 13, 2026
6deb6b9
docs: credit upstream and community plugins
TheOrdinaryWow May 13, 2026
2661c47
refactor: skip whole message when scaffolding markers are present
TheOrdinaryWow May 13, 2026
b4314a8
fix: treat skill invocation bodies as scaffolding
TheOrdinaryWow May 13, 2026
217a7c3
docs: clarify scaffolding filter scope
TheOrdinaryWow May 13, 2026
f83c02b
chore: bump version to 1.1.0
TheOrdinaryWow May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@

Your agent remembers what you tell it — across sessions, across projects.

## Table of Contents

- [Installation](#installation)
- [Features](#features)
- [Tool Usage](#tool-usage)
- [Memory Scoping](#memory-scoping)
- [Configuration](#configuration)
- [Container Tag Selection](#container-tag-selection)
- [Project Tag Strategy](#project-tag-strategy)
- [Usage with Oh My OpenAgent](#usage-with-oh-my-openagent)
- [Development](#development)
- [Logs](#logs)
- [Maintenance](#maintenance)
- [Acknowledgements](#acknowledgements)
- [License](#license)

## Installation

### For Humans
Expand Down Expand Up @@ -177,6 +193,66 @@ API key is <private>sk-abc123</private>

Content in `<private>` tags is never stored.

### Incremental Capture

Assistant turns can be saved as they finish, which keeps long sessions from losing useful context. The capture limit is controlled by `maxCaptureChars`, so very large turns stay bounded.

### Every-Message Recall

This option runs memory search on every user message and re-injects the best matches when they matter. It is off by default because it adds retrieval cost on every turn.

### Signal Extraction

The plugin can watch for signal keywords and keep only the turns that look worth preserving. It stays heuristic-only, so no extra LLM call is needed for capture decisions.

### Content Dedup

Duplicate memories are skipped by content hash so the same fact does not get stored over and over. The cache is bounded and only stores hashes, which keeps the disk footprint small.

### Metadata Stripping

Injected timestamps, tags, and other wrapper metadata are removed before search. Private tags remain untouched, so the plugin still respects explicit private boundaries.

### Relative Time Display

Memory timestamps can render as relative text such as `2 hrs ago` instead of raw ISO strings. That keeps the injected context easier to scan during active sessions.

### Entity Context

Entity guidance gives memory extraction a short, focused hint about the current subject. It helps the plugin keep person, project, and product references consistent without adding extra API calls.

### Auto-Category Tagging

Memories can be classified into categories such as preference, decision, fact, or other. The feature is off by default so categorization only happens when you opt in.

### Memo Usage Footer

A compact footer can show how many memories were injected into the current context. That makes it easier to see when memory usage is high without opening logs.

### Profile Cross-Array Dedup

Profile facts can be deduped across the profile, project, and relevant-memory arrays before injection. That keeps repeated facts from crowding out fresher context.

### Recall Keywords

Extra recall phrases can trigger a search even when the message does not look like a normal memory request. This is useful for project-specific prompts that should always pull context back in.

### Periodic Re-Injection

The plugin can re-inject memory every N completed turns to keep long chats anchored. Set the interval to `0` to disable the cadence entirely.

### Session-End Save

When a session idles or ends, the plugin can write a final memory snapshot. That gives the conversation one last save point even if earlier capture was missed.

### Pre-Compaction Save

Before OpenCode compacts the conversation, the plugin can preserve the current state in full. This keeps the memory timeline intact before summarization trims the active context.

### Post-Compaction Re-Injection

After compaction, the plugin can queue the session for a fresh memory pull on the next chat turn. That restores useful context after the summary pass finishes.

## Tool Usage

The `supermemory` tool is available to the agent:
Expand Down Expand Up @@ -204,6 +280,10 @@ The project tag formula is configurable via [`projectTagStrategy`](#project-tag-

## Configuration

### Migration Notes (v2)

All new features default to safe behavior (zero additional API cost). Three options require explicit opt-in: `everyMessageRecall`, `reinjectEveryN`, and `autoCategoryTagging`.

Create `~/.config/opencode/supermemory-p.jsonc`:

```jsonc
Expand Down Expand Up @@ -246,6 +326,60 @@ Create `~/.config/opencode/supermemory-p.jsonc`:

// Context usage ratio that triggers compaction (0-1)
"compactionThreshold": 0.8,

// Save assistant turns progressively as they finish
"incrementalCapture": true,

// Maximum characters kept from any captured turn
"maxCaptureChars": 5000,

// Run recall search on every message (costly; default off)
"everyMessageRecall": false,

// Re-inject memory every N completed turns (0 disables it)
"reinjectEveryN": 0,

// Re-inject memory after context compaction
"postCompactionReinject": true,

// Save a final snapshot when the session ends or idles
"sessionEndSave": true,

// Keep only turns that match signal keywords
"signalExtraction": true,

// Keywords that trigger capture for high-signal turns
"signalKeywords": ["remember", "save this", "important"],

// Include this many earlier turns before a signal turn
"signalTurnsBefore": 3,

// Extra recall phrases that trigger a memory search
"recallKeywordPatterns": ["bring that back", "look that up"],

// Skip duplicate memory saves by normalized content hash
"dedupEnabled": true,

// Maximum number of entries kept in the dedup cache
"dedupCacheSize": 500,

// Short guidance for entity extraction during capture
"entityContext": "Focus on people, projects, tools, and decisions that matter to this repository.",

// Strip injected metadata from memory search queries
"metadataStripping": true,

// Show relative timestamps like '2 hrs ago' in memory context
"relativeTimeDisplay": true,

// Append a compact memory-count footer to injected context
"memoUsageFooter": true,

// Classify memories into categories before storing them
"autoCategoryTagging": false,

// Deduplicate profile facts across profile, project, and relevant memories
"profileCrossArrayDedup": true,
}
```

Expand Down Expand Up @@ -321,6 +455,8 @@ Add to `~/.config/opencode/oh-my-openagent.json`:
}
```

Messages containing plugin or orchestrator scaffolding (slash-command expansions, system reminders, `<Work_Context>` blocks, skill bodies, session-context wrappers, mode indicators, etc.) are skipped entirely from the capture stream. Memories ingested with this plugin enabled will not contain other plugins' markers, so no manual cleanup is needed for new sessions. To clean up memories captured before this filtering existed, see [Maintenance](#maintenance).

## Development

```bash
Expand All @@ -345,6 +481,37 @@ Local install:
tail -f ~/.local/share/opencode-supermemory-p/log/main.log
```

## Maintenance

### Purge legacy plugin-injected memories

Memories captured by earlier versions of this plugin may contain content injected by other plugins (slash-command expansions, system reminders, etc.). The `purge-injected` script scans the Supermemory backend and removes them.

Dry-run (default — lists matches without deleting):

```bash
bun run scripts/purge-injected.ts
```

Confirm deletion:

```bash
bun run scripts/purge-injected.ts --confirm
```

The script reads `SUPERMEMORY_API_KEY` from the environment or `~/.config/opencode/supermemory-p.jsonc`. Override with `--api-key sm_...` or `--base-url https://...` if needed.

## Acknowledgements

This plugin builds on the work of the Supermemory team and the wider community of plugin authors. In particular:

- [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) — the upstream OpenCode plugin this fork is based on.
- [claude-supermemory](https://github.com/supermemoryai/claude-supermemory) — source of the entity-context, dedup, and signal-extraction patterns.
- [openclaw-supermemory](https://github.com/supermemoryai/openclaw-supermemory) — source of the incremental-capture, metadata-stripping, and compaction-hook designs.
- [opencode-supermemory-max](https://github.com/kandotrun/opencode-supermemory-max) — community fork that informed several of the feature consolidations here.

Thanks to everyone who shipped these projects.

## License

MIT
113 changes: 111 additions & 2 deletions assets/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/TheOrdinaryWow/opencode-supermemory-p/refs/heads/main/assets/config.schema.json",
"title": "opencode-supermemory-p config",
"description": "opencode-supermemory-p's configuration schema.",
"description": "Configuration for opencode-supermemory-p.",
"type": "object",
"required": [],
"additionalProperties": false,
"properties": {
"$schema": {
"type": "string",
"description": "opencode-supermemory-p's JSON Schema reference."
"description": "JSON Schema reference for editor validation."
},
"apiKey": {
"type": "string",
Expand Down Expand Up @@ -75,6 +75,115 @@
"type": "number",
"exclusiveMinimum": 0,
"maximum": 1
},
"incrementalCapture": {
"default": true,
"type": "boolean"
},
"maxCaptureChars": {
"default": 5000,
"type": "number",
"exclusiveMinimum": 0
},
"postCompactionReinject": {
"default": true,
"type": "boolean"
},
"sessionEndSave": {
"default": true,
"type": "boolean"
},
"signalExtraction": {
"default": true,
"type": "boolean"
},
"signalKeywords": {
"default": [
"remember",
"important",
"save this",
"note this",
"don't forget",
"key decision",
"project info",
"my name",
"I work",
"I prefer",
"I use",
"I like",
"always",
"never",
"my team",
"my email",
"my company"
],
"type": "array",
"items": {
"type": "string"
}
},
"signalTurnsBefore": {
"default": 3,
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"recallKeywordPatterns": {
"default": [
"what did we",
"remind me",
"earlier you said",
"what was the",
"do you remember"
],
"type": "array",
"items": {
"type": "string"
}
},
"dedupEnabled": {
"default": true,
"type": "boolean"
},
"dedupCacheSize": {
"default": 500,
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"entityContext": {
"default": "User-assistant conversation. Format: [role: user]...[user:end] and [role: assistant]...[assistant:end].\n\nOnly extract things useful in FUTURE conversations. Most messages are not worth remembering.\n\nREMEMBER: lasting personal facts — dietary restrictions, preferences, personal details, workplace, location, tools, ongoing projects, routines, explicit \"remember this\" requests.\n\nDO NOT REMEMBER: temporary intents, one-time tasks, assistant actions (searching, writing files, generating code), assistant suggestions, implementation details, in-progress task status.\n\nRULES:\n- Assistant output is CONTEXT ONLY — never attribute assistant actions to the user\n- \"find X\" or \"do Y\" = one-time request, NOT a memory\n- Only store preferences explicitly stated (\"I like...\", \"I prefer...\", \"I always...\")\n- When in doubt, do NOT create a memory. Less is more.",
"type": "string"
},
"metadataStripping": {
"default": true,
"type": "boolean"
},
"relativeTimeDisplay": {
"default": true,
"type": "boolean"
},
"memoUsageFooter": {
"default": true,
"type": "boolean"
},
"profileCrossArrayDedup": {
"default": true,
"type": "boolean"
},
"everyMessageRecall": {
"default": false,
"type": "boolean"
},
"reinjectEveryN": {
"default": 0,
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"autoCategoryTagging": {
"default": false,
"type": "boolean"
}
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "opencode-supermemory-p",
"version": "1.0.0",
"version": "1.1.0",
"description": "The powered Supermemory plugin for OpenCode — persistent memory for coding agents",
"type": "module",
"main": "./dist/index.js",
Expand Down
Loading
Loading