@memoryrelay/plugin-memoryrelay-ai 0.12.10 → 0.13.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 +71 -546
- package/index.ts +642 -16
- package/openclaw.plugin.json +28 -2
- package/package.json +3 -2
- package/skills/codebase-navigation/SKILL.md +105 -0
- package/skills/decision-tracking/SKILL.md +50 -0
- package/skills/entity-and-context/SKILL.md +62 -0
- package/skills/memory-workflow/SKILL.md +84 -0
- package/skills/pattern-management/SKILL.md +57 -0
- package/skills/project-orchestration/SKILL.md +72 -0
- package/skills/release-process/SKILL.md +83 -0
- package/skills/testing-memoryrelay/SKILL.md +87 -0
package/openclaw.plugin.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"id": "plugin-memoryrelay-ai",
|
|
3
3
|
"kind": "memory",
|
|
4
4
|
"name": "MemoryRelay AI",
|
|
5
|
-
"description": "MemoryRelay v0.
|
|
6
|
-
"version": "0.
|
|
5
|
+
"description": "MemoryRelay v0.13.0 - Long-term memory with sessions, decisions, patterns & projects (api.memoryrelay.net)",
|
|
6
|
+
"version": "0.13.0",
|
|
7
7
|
"uiHints": {
|
|
8
8
|
"apiKey": {
|
|
9
9
|
"label": "MemoryRelay API Key",
|
|
@@ -45,6 +45,18 @@
|
|
|
45
45
|
"label": "Exclude Channels",
|
|
46
46
|
"help": "List of channel IDs to skip auto-recall (e.g., ['whatsapp:group_123', 'telegram:456'])",
|
|
47
47
|
"advanced": true
|
|
48
|
+
},
|
|
49
|
+
"sessionTimeoutMinutes": {
|
|
50
|
+
"label": "Session Timeout (minutes)",
|
|
51
|
+
"placeholder": "120",
|
|
52
|
+
"advanced": true,
|
|
53
|
+
"help": "Auto-close MemoryRelay sessions inactive for this many minutes (default: 120)"
|
|
54
|
+
},
|
|
55
|
+
"sessionCleanupIntervalMinutes": {
|
|
56
|
+
"label": "Cleanup Interval (minutes)",
|
|
57
|
+
"placeholder": "30",
|
|
58
|
+
"advanced": true,
|
|
59
|
+
"help": "How often to check for stale sessions (default: 30)"
|
|
48
60
|
}
|
|
49
61
|
},
|
|
50
62
|
"configSchema": {
|
|
@@ -101,6 +113,20 @@
|
|
|
101
113
|
"default": [],
|
|
102
114
|
"description": "List of channel IDs to exclude from auto-recall"
|
|
103
115
|
},
|
|
116
|
+
"sessionTimeoutMinutes": {
|
|
117
|
+
"type": "number",
|
|
118
|
+
"default": 120,
|
|
119
|
+
"minimum": 10,
|
|
120
|
+
"maximum": 1440,
|
|
121
|
+
"description": "Auto-close sessions inactive for this many minutes"
|
|
122
|
+
},
|
|
123
|
+
"sessionCleanupIntervalMinutes": {
|
|
124
|
+
"type": "number",
|
|
125
|
+
"default": 30,
|
|
126
|
+
"minimum": 5,
|
|
127
|
+
"maximum": 360,
|
|
128
|
+
"description": "How often to check for stale sessions (minutes)"
|
|
129
|
+
},
|
|
104
130
|
"debug": {
|
|
105
131
|
"type": "boolean",
|
|
106
132
|
"default": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memoryrelay/plugin-memoryrelay-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "OpenClaw memory plugin for MemoryRelay API - sessions, decisions, patterns, projects & semantic search",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"openclaw.plugin.json",
|
|
49
49
|
"README.md",
|
|
50
50
|
"LICENSE",
|
|
51
|
-
"src/"
|
|
51
|
+
"src/",
|
|
52
|
+
"skills/"
|
|
52
53
|
],
|
|
53
54
|
"engines": {
|
|
54
55
|
"node": ">=20.0.0"
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codebase-navigation
|
|
3
|
+
description: "Use when navigating the openclaw-plugin codebase for the first time, looking for where a tool is registered, understanding the monolithic index.ts structure, or adding a new tool or hook."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Codebase Navigation
|
|
7
|
+
|
|
8
|
+
The plugin is a single monolithic `index.ts` (4839 lines) plus a few extracted modules.
|
|
9
|
+
|
|
10
|
+
## index.ts File Map
|
|
11
|
+
|
|
12
|
+
| Lines | Section |
|
|
13
|
+
|-------|---------|
|
|
14
|
+
| 1--14 | Header comments and version info |
|
|
15
|
+
| 16--36 | Imports (plugin SDK, heartbeat, CLI stats, onboarding) |
|
|
16
|
+
| 38--47 | Constants (`DEFAULT_API_URL`, `REQUEST_TIMEOUT_MS`, `MAX_RETRIES`) |
|
|
17
|
+
| 48--121 | `DebugLogger` class (inlined) with `LogEntry`, `DebugLoggerConfig` |
|
|
18
|
+
| 123--404 | `StatusReporter` class (inlined) with `ToolStatus`, `ConnectionStatus`, `MemoryStats` |
|
|
19
|
+
| 406--461 | Types: `AutoCaptureConfig`, `MemoryRelayConfig`, `Memory`, `SearchResult`, `Stats` |
|
|
20
|
+
| 463--648 | Utility functions: `sleep`, `isRetryableError`, `fetchWithTimeout`, auto-capture helpers, `redactSensitive`, `extractRescueContent` |
|
|
21
|
+
| 650--1294 | `MemoryRelayClient` class (API client with retry logic, all endpoints) |
|
|
22
|
+
| 1296--1315 | Pattern detection for auto-capture (`CAPTURE_PATTERNS`, `shouldCapture`) |
|
|
23
|
+
| 1317--1562 | Plugin entry: `export default async function plugin(api)`, config resolution, client init, session cache, `touchSession` |
|
|
24
|
+
| 1564--1613 | `TOOL_GROUPS` map and `isToolEnabled()` |
|
|
25
|
+
| 1615--3747 | 39 tool registrations |
|
|
26
|
+
| 3749--3853 | CLI commands (`memoryrelay status/stats/list/export`) |
|
|
27
|
+
| 3855--4240 | 14 lifecycle hooks (`before_agent_start`, `agent_end`, `session_start`, `session_end`, `before_tool_call`, `after_tool_call`, `before_compaction`, `before_reset`, `message_received`, `message_sending`, `before_message_write`, `subagent_spawned`, `subagent_ended`, `tool_result_persist`) |
|
|
28
|
+
| 4242--4274 | First-run onboarding |
|
|
29
|
+
| 4276--4586 | Gateway methods (`memoryrelay.logs`, `.health`, `.metrics`, `.heartbeat`, `.onboarding`, `.stats`, `.test`) |
|
|
30
|
+
| 4588--4790 | Direct commands: `/memory-status`, `/memory-stats`, `/memory-health`, `/memory-logs`, `/memory-metrics` |
|
|
31
|
+
| 4792--4839 | Stale session cleanup service (`memoryrelay-session-cleanup` via `api.registerService`) |
|
|
32
|
+
|
|
33
|
+
## Tool Registration Pattern
|
|
34
|
+
|
|
35
|
+
Every tool follows this pattern:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
if (isToolEnabled("tool_name")) {
|
|
39
|
+
api.registerTool((ctx) => ({
|
|
40
|
+
name: "tool_name",
|
|
41
|
+
description: "...",
|
|
42
|
+
parameters: { /* JSON schema */ },
|
|
43
|
+
execute: async (_id, args) => { /* impl */ }
|
|
44
|
+
}), { name: "tool_name" });
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Tools are numbered 1--39 with comment markers (e.g., `// 1. memory_store`). Search for `// N.` to jump to a specific tool.
|
|
49
|
+
|
|
50
|
+
## TOOL_GROUPS (line 1569)
|
|
51
|
+
|
|
52
|
+
| Group | Count | Tools |
|
|
53
|
+
|-------|-------|-------|
|
|
54
|
+
| memory | 9 | `memory_store`, `memory_recall`, `memory_forget`, `memory_list`, `memory_get`, `memory_update`, `memory_batch_store`, `memory_context`, `memory_promote` |
|
|
55
|
+
| entity | 4 | `entity_create`, `entity_link`, `entity_list`, `entity_graph` |
|
|
56
|
+
| agent | 3 | `agent_list`, `agent_create`, `agent_get` |
|
|
57
|
+
| session | 4 | `session_start`, `session_end`, `session_recall`, `session_list` |
|
|
58
|
+
| decision | 4 | `decision_record`, `decision_list`, `decision_supersede`, `decision_check` |
|
|
59
|
+
| pattern | 4 | `pattern_create`, `pattern_search`, `pattern_adopt`, `pattern_suggest` |
|
|
60
|
+
| project | 10 | `project_register`, `project_list`, `project_info`, `project_add_relationship`, `project_dependencies`, `project_dependents`, `project_related`, `project_impact`, `project_shared_patterns`, `project_context` |
|
|
61
|
+
| health | 1 | `memory_health` |
|
|
62
|
+
|
|
63
|
+
The `enabledTools` config option accepts a comma-separated list of group names (or `"all"`).
|
|
64
|
+
|
|
65
|
+
## Supporting Modules
|
|
66
|
+
|
|
67
|
+
| File | Purpose |
|
|
68
|
+
|------|---------|
|
|
69
|
+
| `src/debug-logger.ts` | `DebugLogger` class (source of the inlined copy) |
|
|
70
|
+
| `src/status-reporter.ts` | `StatusReporter` class (source of the inlined copy) |
|
|
71
|
+
| `src/heartbeat/daily-stats.ts` | Morning/evening summaries, `calculateStats`, `formatStatsForDisplay` |
|
|
72
|
+
| `src/onboarding/first-run.ts` | Onboarding wizard: `checkFirstRun`, `runSimpleOnboarding` |
|
|
73
|
+
| `src/cli/stats-command.ts` | CLI `stats` command handler |
|
|
74
|
+
|
|
75
|
+
## Configuration Fallback Chain
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Plugin config (openclaw.json) -> Env vars -> Defaults
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `apiKey`: `cfg.apiKey` -> `MEMORYRELAY_API_KEY` (required, no default)
|
|
82
|
+
- `agentId`: `cfg.agentId` -> `MEMORYRELAY_AGENT_ID` -> `api.agentName`
|
|
83
|
+
- `apiUrl`: `cfg.apiUrl` -> `MEMORYRELAY_API_URL` -> `https://api.memoryrelay.net`
|
|
84
|
+
|
|
85
|
+
## Key Types
|
|
86
|
+
|
|
87
|
+
| Type | Location | Purpose |
|
|
88
|
+
|------|----------|---------|
|
|
89
|
+
| `Memory` | L442 | Core memory record (`id`, `content`, `agent_id`, `metadata`, `entities`) |
|
|
90
|
+
| `SearchResult` | L453 | Vector search hit (`memory`, `score`) |
|
|
91
|
+
| `Stats` | L458 | Agent statistics (`total_memories`, `last_updated`) |
|
|
92
|
+
| `LogEntry` | L52 | Debug log entry (tool, method, path, duration, status) |
|
|
93
|
+
| `DebugLoggerConfig` | L66 | Logger settings (enabled, verbose, maxEntries) |
|
|
94
|
+
| `ConnectionStatus` | L140 | API connection state (status, endpoint, responseTime) |
|
|
95
|
+
| `ToolStatus` | L127 | Per-group tool health (enabled, available, failed) |
|
|
96
|
+
|
|
97
|
+
## Key Helpers
|
|
98
|
+
|
|
99
|
+
| Function | Location | Purpose |
|
|
100
|
+
|----------|----------|---------|
|
|
101
|
+
| `redactSensitive` | L591 | Replace blocklist patterns with `[REDACTED]` |
|
|
102
|
+
| `extractRescueContent` | L608 | Salvage assistant messages before compaction/reset |
|
|
103
|
+
| `touchSession` | L1444 | Update `lastActivityAt` timestamp in session cache |
|
|
104
|
+
| `isToolEnabled` | L1605 | Check if a tool's group is in the enabled set |
|
|
105
|
+
| `shouldCapture` | L1310 | Test text against `CAPTURE_PATTERNS` for auto-capture |
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: decision-tracking
|
|
3
|
+
description: "Use when making architectural choices, evaluating alternatives, revisiting past decisions, or needing to check whether a decision already exists before committing to a direction."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Decision Tracking
|
|
7
|
+
|
|
8
|
+
Decisions are **choices with rationale and alternatives considered**. Plain facts, findings, or information are memories — use `memory_store` for those.
|
|
9
|
+
|
|
10
|
+
## Decision Tools
|
|
11
|
+
|
|
12
|
+
| Tool | Signature | Purpose |
|
|
13
|
+
|------|-----------|---------|
|
|
14
|
+
| `decision_record` | `decision_record(title, rationale, project)` | Record a new decision with reasoning |
|
|
15
|
+
| `decision_list` | `decision_list(project)` | List all decisions for a project |
|
|
16
|
+
| `decision_supersede` | `decision_supersede(old_id, new_title, new_rationale)` | Replace an outdated decision |
|
|
17
|
+
| `decision_check` | `decision_check(query, project)` | Check for conflicting decisions before choosing |
|
|
18
|
+
|
|
19
|
+
## Workflow
|
|
20
|
+
|
|
21
|
+
1. **Check first** — Always call `decision_check(query, project)` before making an architectural choice. This surfaces existing decisions that may conflict or already cover the topic.
|
|
22
|
+
2. **Record with rationale** — Use `decision_record(title, rationale, project)`. The rationale should include why this option was chosen and what alternatives were rejected.
|
|
23
|
+
3. **Supersede, don't duplicate** — When a decision changes, call `decision_supersede(old_id, new_title, new_rationale)`. This preserves history while marking the old decision as replaced.
|
|
24
|
+
4. **Review periodically** — Use `decision_list(project)` to audit active decisions during planning or refactoring.
|
|
25
|
+
|
|
26
|
+
## Project Scoping
|
|
27
|
+
|
|
28
|
+
Decisions must be scoped to the relevant project:
|
|
29
|
+
|
|
30
|
+
- Set `defaultProject` in plugin config to avoid passing `project` on every call.
|
|
31
|
+
- Pass `project` explicitly when working across multiple projects.
|
|
32
|
+
- Unscoped decisions pollute search results and create false conflicts.
|
|
33
|
+
|
|
34
|
+
## Decisions vs Memories
|
|
35
|
+
|
|
36
|
+
| Store as Decision | Store as Memory |
|
|
37
|
+
|-------------------|-----------------|
|
|
38
|
+
| "Use PostgreSQL over MongoDB for user data" | "PostgreSQL supports JSONB columns" |
|
|
39
|
+
| "Adopt ESM modules, drop CommonJS" | "Node 20 supports ESM natively" |
|
|
40
|
+
| "API versioning via URL path, not headers" | "Team prefers REST over GraphQL" |
|
|
41
|
+
|
|
42
|
+
## Common Mistakes
|
|
43
|
+
|
|
44
|
+
| Mistake | Fix |
|
|
45
|
+
|---------|-----|
|
|
46
|
+
| Recording decisions with `memory_store` | Use `decision_record` — decisions need rationale tracking and conflict detection |
|
|
47
|
+
| Making choices without `decision_check` | Always check first; conflicting decisions cause inconsistent architecture |
|
|
48
|
+
| Adding a new decision when one already exists | Use `decision_supersede` to replace the old decision, preserving history |
|
|
49
|
+
| Omitting the `project` parameter | Scope every decision to a project via parameter or `defaultProject` config |
|
|
50
|
+
| Storing facts as decisions | Only choices with rationale belong in decisions; use `memory_store` for information |
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: entity-and-context
|
|
3
|
+
description: "Use when building relationship maps between people, systems, services, or concepts that appear across multiple memories, or when recalling information that benefits from entity connections rather than flat search."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Entity and Context
|
|
7
|
+
|
|
8
|
+
Entities turn flat memory storage into a connected knowledge graph. Create entities for **named things that recur across multiple memories** and benefit from relationship tracking.
|
|
9
|
+
|
|
10
|
+
## Relevant Tools
|
|
11
|
+
|
|
12
|
+
| Tool | Signature | Purpose |
|
|
13
|
+
|------|-----------|---------|
|
|
14
|
+
| `entity_create` | `entity_create(name, type, description)` | Create a new entity node |
|
|
15
|
+
| `entity_link` | `entity_link(entity_id, memory_id)` | Connect an entity to a memory |
|
|
16
|
+
| `entity_list` | `entity_list(type?)` | List entities, optionally filtered by type |
|
|
17
|
+
| `entity_graph` | `entity_graph(entity_id)` | Visualize an entity's relationships |
|
|
18
|
+
| `memory_context` | `memory_context(query)` | Enriched recall with entity connections (memory group tool) |
|
|
19
|
+
|
|
20
|
+
## Entity Types
|
|
21
|
+
|
|
22
|
+
| Type | Examples |
|
|
23
|
+
|------|----------|
|
|
24
|
+
| `people` | Team members, stakeholders, external contacts |
|
|
25
|
+
| `systems` | Databases, cloud platforms, internal tools |
|
|
26
|
+
| `services` | APIs, microservices, third-party integrations |
|
|
27
|
+
| `concepts` | Architecture patterns, business domains, protocols |
|
|
28
|
+
| `teams` | Engineering squads, departments, working groups |
|
|
29
|
+
| `repositories` | Codebases, monorepos, package libraries |
|
|
30
|
+
|
|
31
|
+
## When to Create Entities
|
|
32
|
+
|
|
33
|
+
Create an entity when a named thing:
|
|
34
|
+
- Appears in **2+ memories** (not one-off mentions)
|
|
35
|
+
- Has relationships worth tracking (owns, depends on, maintains)
|
|
36
|
+
- Would benefit from graph traversal during recall
|
|
37
|
+
|
|
38
|
+
## Linking Workflow
|
|
39
|
+
|
|
40
|
+
1. **Create the entity** — `entity_create("AuthService", "services", "Handles OAuth2 and JWT token management")`
|
|
41
|
+
2. **Store related memories** — `memory_store(content, metadata)` as usual
|
|
42
|
+
3. **Link them** — `entity_link(entity_id, memory_id)` to connect entity to each relevant memory
|
|
43
|
+
4. **Query with context** — `memory_context("authentication flow")` returns memories enriched with linked entity data
|
|
44
|
+
5. **Explore connections** — `entity_graph(entity_id)` to see all related memories and co-linked entities
|
|
45
|
+
|
|
46
|
+
## memory_context vs memory_recall
|
|
47
|
+
|
|
48
|
+
| Use `memory_recall` | Use `memory_context` |
|
|
49
|
+
|---------------------|----------------------|
|
|
50
|
+
| Simple keyword/semantic search | Need entity relationships in results |
|
|
51
|
+
| No entities involved | Entities are linked to relevant memories |
|
|
52
|
+
| Quick lookup of isolated facts | Understanding how things connect |
|
|
53
|
+
|
|
54
|
+
## Common Mistakes
|
|
55
|
+
|
|
56
|
+
| Mistake | Fix |
|
|
57
|
+
|---------|-----|
|
|
58
|
+
| Creating entities for one-off mentions | Only create entities for things referenced across multiple memories |
|
|
59
|
+
| Not linking entities to memories | An unlinked entity is invisible to `memory_context`; always link after creating |
|
|
60
|
+
| Using `memory_recall` when entities exist | Switch to `memory_context` for richer results that include entity connections |
|
|
61
|
+
| Creating duplicate entities | Call `entity_list(type)` first to check if the entity already exists |
|
|
62
|
+
| Linking everything to one entity | Keep links specific; an entity should connect only to directly relevant memories |
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-workflow
|
|
3
|
+
description: "Use when starting a new conversation or task that needs persistent memory, storing or retrieving information across sessions, or working within a project that uses MemoryRelay."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Workflow
|
|
7
|
+
|
|
8
|
+
Follow this order every time. Skipping steps causes orphaned memories.
|
|
9
|
+
|
|
10
|
+
## Startup Sequence
|
|
11
|
+
|
|
12
|
+
| Step | Call | Purpose |
|
|
13
|
+
|------|------|---------|
|
|
14
|
+
| 1 | `project_context(project)` | Load hot-tier memories, active decisions, adopted patterns |
|
|
15
|
+
| 2 | `session_start(title, project)` | Begin tracking work (returns `session_id`) |
|
|
16
|
+
| 3 | `decision_check(query, project)` | Check existing decisions before architectural choices |
|
|
17
|
+
| 4 | `pattern_search(query)` | Find established conventions |
|
|
18
|
+
|
|
19
|
+
## During Work
|
|
20
|
+
|
|
21
|
+
| Action | Tool | Notes |
|
|
22
|
+
|--------|------|-------|
|
|
23
|
+
| Save info | `memory_store(content, metadata)` | Always set `deduplicate=true` |
|
|
24
|
+
| Search | `memory_recall(query)` | Semantic search across memories |
|
|
25
|
+
| Delete | `memory_forget(id_or_query)` | By ID or fuzzy search |
|
|
26
|
+
| Browse | `memory_list(limit, offset)` | Chronological listing |
|
|
27
|
+
| Read one | `memory_get(id)` | Fetch by exact ID |
|
|
28
|
+
| Edit | `memory_update(id, content)` | Correct or expand existing |
|
|
29
|
+
| Bulk save | `memory_batch_store(memories[])` | Efficient for multiple items |
|
|
30
|
+
| Build prompt | `memory_context(query, token_budget)` | Token-aware context window |
|
|
31
|
+
| Upgrade | `memory_promote(id, importance, tier)` | Move temporary to long-term |
|
|
32
|
+
|
|
33
|
+
## Ending a Session
|
|
34
|
+
|
|
35
|
+
Call `session_end(session_id, summary)` with a meaningful summary. This becomes the historical record.
|
|
36
|
+
|
|
37
|
+
## Deduplication
|
|
38
|
+
|
|
39
|
+
Always pass `deduplicate=true` on `memory_store` and `memory_batch_store`. The default threshold is 0.9 similarity. Skipping this clutters search results with near-duplicates.
|
|
40
|
+
|
|
41
|
+
## Metadata Best Practices
|
|
42
|
+
|
|
43
|
+
Always include `category` and `tags` in metadata:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
metadata: { "category": "technical", "tags": "auth, api", "source": "code-review" }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Categories: `technical`, `preference`, `credential`, `decision`. Consistent metadata makes filtering reliable.
|
|
50
|
+
|
|
51
|
+
## Memory Tiers and Promotion
|
|
52
|
+
|
|
53
|
+
| Tier | Retention | Use for |
|
|
54
|
+
|------|-----------|---------|
|
|
55
|
+
| `hot` | Always loaded by `project_context` | Critical project facts |
|
|
56
|
+
| `warm` | Retrieved by search | General knowledge |
|
|
57
|
+
| `cold` | Archived, low priority | Historical notes |
|
|
58
|
+
|
|
59
|
+
Use `memory_promote(id, importance, tier)` to upgrade a memory. Set `importance` near 1.0 for critical items.
|
|
60
|
+
|
|
61
|
+
## Auto-Capture Tiers
|
|
62
|
+
|
|
63
|
+
Configured per-plugin, not per-call. Know what mode is active:
|
|
64
|
+
|
|
65
|
+
| Tier | Behavior |
|
|
66
|
+
|------|----------|
|
|
67
|
+
| `off` | No automatic capture |
|
|
68
|
+
| `conservative` | Only credentials and explicit preferences |
|
|
69
|
+
| `smart` (default) | Technical facts, preferences, patterns |
|
|
70
|
+
| `aggressive` | Captures most exchanged information |
|
|
71
|
+
|
|
72
|
+
## Privacy Blocklist
|
|
73
|
+
|
|
74
|
+
Auto-filtered (never stored): passwords, credit card numbers, SSNs, API keys/tokens. The blocklist regex rejects these even on manual `memory_store` calls.
|
|
75
|
+
|
|
76
|
+
## Common Mistakes
|
|
77
|
+
|
|
78
|
+
| Mistake | Fix |
|
|
79
|
+
|---------|-----|
|
|
80
|
+
| Storing without a session | Always call `session_start` first |
|
|
81
|
+
| Skipping `deduplicate=true` | Set it on every `memory_store` call |
|
|
82
|
+
| Using `memory_store` for decisions | Use `decision_record` instead |
|
|
83
|
+
| No category/tags in metadata | Always include both for searchability |
|
|
84
|
+
| Storing API keys or passwords | Blocklist rejects them; use a secrets manager |
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pattern-management
|
|
3
|
+
description: "Use when establishing reusable conventions, looking up existing patterns before implementing a solution, adopting shared patterns across projects, or getting pattern recommendations for a project."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pattern Management
|
|
7
|
+
|
|
8
|
+
Patterns are **reusable solutions with problem context**. Plain implementation notes are memories — use `memory_store` for those.
|
|
9
|
+
|
|
10
|
+
## Pattern Tools
|
|
11
|
+
|
|
12
|
+
| Tool | Signature | Purpose |
|
|
13
|
+
|------|-----------|---------|
|
|
14
|
+
| `pattern_create` | `pattern_create(title, description)` | Create a reusable pattern |
|
|
15
|
+
| `pattern_search` | `pattern_search(query)` | Find existing patterns before creating new ones |
|
|
16
|
+
| `pattern_adopt` | `pattern_adopt(pattern_id, project)` | Track which projects use which patterns |
|
|
17
|
+
| `pattern_suggest` | `pattern_suggest(project)` | Get pattern recommendations for a project |
|
|
18
|
+
|
|
19
|
+
## Workflow
|
|
20
|
+
|
|
21
|
+
1. **Search first** — Always call `pattern_search(query)` before `pattern_create`. Duplicate patterns fragment conventions and confuse future lookups.
|
|
22
|
+
2. **Create with structure** — If no match exists, call `pattern_create(title, description)`. The description must follow the structure below.
|
|
23
|
+
3. **Adopt to projects** — Call `pattern_adopt(pattern_id, project)` so the pattern appears in `project_context` results and `pattern_suggest` recommendations.
|
|
24
|
+
4. **Review suggestions** — Use `pattern_suggest(project)` when starting work on a project to discover applicable conventions.
|
|
25
|
+
|
|
26
|
+
## Pattern Structure
|
|
27
|
+
|
|
28
|
+
Every `description` in `pattern_create` should include:
|
|
29
|
+
|
|
30
|
+
| Section | Content |
|
|
31
|
+
|---------|---------|
|
|
32
|
+
| **Problem** | What recurring issue this solves |
|
|
33
|
+
| **Solution** | The reusable approach or convention |
|
|
34
|
+
| **Context** | When to apply (and when not to) |
|
|
35
|
+
| **Examples** | Concrete usage showing the pattern in action |
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
description: "Problem: Inconsistent error responses across API endpoints.
|
|
39
|
+
Solution: Return { error: string, code: string, details?: object } on all 4xx/5xx.
|
|
40
|
+
Context: REST APIs with multiple consumers. Not needed for internal RPC.
|
|
41
|
+
Examples: 400 → { error: 'Invalid email', code: 'VALIDATION_ERROR' }"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Cross-Project Consistency
|
|
45
|
+
|
|
46
|
+
- `pattern_adopt(pattern_id, project)` links a pattern to a project. Multiple projects can adopt the same pattern.
|
|
47
|
+
- `pattern_suggest(project)` returns unadopted patterns that may be relevant based on project context.
|
|
48
|
+
- Adopted patterns load automatically via `project_context`, keeping teams aligned without manual lookups.
|
|
49
|
+
|
|
50
|
+
## Common Mistakes
|
|
51
|
+
|
|
52
|
+
| Mistake | Fix |
|
|
53
|
+
|---------|-----|
|
|
54
|
+
| Creating without searching first | Always `pattern_search` before `pattern_create` — duplicates fragment conventions |
|
|
55
|
+
| Vague descriptions | Follow the Problem/Solution/Context/Examples structure; be specific and actionable |
|
|
56
|
+
| Not adopting to projects | Call `pattern_adopt` after creating; unadopted patterns are invisible to `project_context` |
|
|
57
|
+
| Patterns too specific | Patterns should generalize across contexts; one-off solutions belong in memories or decisions |
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: project-orchestration
|
|
3
|
+
description: "Use when registering a new project, loading project context before starting work, checking cross-project dependencies or impact before breaking changes, or managing relationships between projects."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Project Orchestration
|
|
7
|
+
|
|
8
|
+
Projects are the top-level organizer. Every session, memory, decision, and pattern ties back to a project slug.
|
|
9
|
+
|
|
10
|
+
## Project Tools
|
|
11
|
+
|
|
12
|
+
| Tool | Signature | Purpose |
|
|
13
|
+
|------|-----------|---------|
|
|
14
|
+
| `project_register` | `project_register(slug, name, description, stack)` | Register a new project |
|
|
15
|
+
| `project_list` | `project_list()` | List all registered projects |
|
|
16
|
+
| `project_info` | `project_info(slug)` | Get project details |
|
|
17
|
+
| `project_add_relationship` | `project_add_relationship(from, to, type)` | Link related projects |
|
|
18
|
+
| `project_dependencies` | `project_dependencies(slug)` | What this project depends on |
|
|
19
|
+
| `project_dependents` | `project_dependents(slug)` | What depends on this project |
|
|
20
|
+
| `project_related` | `project_related(slug)` | All related projects (any direction) |
|
|
21
|
+
| `project_impact` | `project_impact(slug)` | Impact analysis before breaking changes |
|
|
22
|
+
| `project_shared_patterns` | `project_shared_patterns(slug)` | Patterns shared across related projects |
|
|
23
|
+
| `project_context` | `project_context(slug)` | Full overview: hot-tier memories, active decisions, adopted patterns |
|
|
24
|
+
|
|
25
|
+
## First-Time Setup
|
|
26
|
+
|
|
27
|
+
1. Call `project_list()` to see existing projects.
|
|
28
|
+
2. If your project is not listed, call `project_register(slug, name, description, stack)`.
|
|
29
|
+
3. If it exists, proceed — do not register duplicates.
|
|
30
|
+
|
|
31
|
+
## defaultProject Config
|
|
32
|
+
|
|
33
|
+
When `defaultProject` is set in plugin configuration, the project slug is **auto-applied** to sessions, decisions, and memories. You do not need to pass the project parameter explicitly on each call — it is injected automatically.
|
|
34
|
+
|
|
35
|
+
## Context Loading
|
|
36
|
+
|
|
37
|
+
Always call `project_context(slug)` as the **first step** when beginning work on a project. It returns:
|
|
38
|
+
|
|
39
|
+
- **Hot-tier memories** — critical facts always surfaced
|
|
40
|
+
- **Active decisions** — current architectural choices
|
|
41
|
+
- **Adopted patterns** — conventions in use
|
|
42
|
+
|
|
43
|
+
This replaces manual searching. Start here, then drill into specifics with other tools.
|
|
44
|
+
|
|
45
|
+
## Impact Analysis
|
|
46
|
+
|
|
47
|
+
Before making **any breaking change**, call `project_impact(slug)`. It checks:
|
|
48
|
+
|
|
49
|
+
- Downstream dependents that will be affected
|
|
50
|
+
- Shared patterns that may need updating
|
|
51
|
+
- Active decisions that may conflict
|
|
52
|
+
|
|
53
|
+
Never skip this step. Breaking a dependency without checking impact creates cascading failures.
|
|
54
|
+
|
|
55
|
+
## Managing Relationships
|
|
56
|
+
|
|
57
|
+
Use `project_add_relationship(from, to, type)` to declare how projects relate. Relationship types include dependencies, shared ownership, and related context. Once linked:
|
|
58
|
+
|
|
59
|
+
- `project_dependencies(slug)` — upstream projects this one relies on
|
|
60
|
+
- `project_dependents(slug)` — downstream projects relying on this one
|
|
61
|
+
- `project_related(slug)` — all connections regardless of direction
|
|
62
|
+
- `project_shared_patterns(slug)` — patterns adopted by both this project and its related projects
|
|
63
|
+
|
|
64
|
+
## Common Mistakes
|
|
65
|
+
|
|
66
|
+
| Mistake | Fix |
|
|
67
|
+
|---------|-----|
|
|
68
|
+
| Working without project context | Always `project_context` first — it loads everything you need |
|
|
69
|
+
| Registering duplicate projects | Call `project_list` before `project_register`; check if slug exists |
|
|
70
|
+
| Not using relationships | Call `project_add_relationship` when projects share code, APIs, or conventions |
|
|
71
|
+
| Breaking changes without impact check | Always `project_impact` before modifying shared interfaces or dependencies |
|
|
72
|
+
| Passing project on every call when `defaultProject` is set | Unnecessary — the config injects it automatically |
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release-process
|
|
3
|
+
description: "Use when bumping the plugin version, preparing a release, updating the CHANGELOG, creating a pre-release audit branch, or triggering the NPM publish workflow."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Release Process
|
|
7
|
+
|
|
8
|
+
## Semantic Versioning (0.x series)
|
|
9
|
+
|
|
10
|
+
| Bump | When | Example |
|
|
11
|
+
|------|------|---------|
|
|
12
|
+
| **Patch** (0.x.Y) | Bug fixes, version string updates, doc fixes | 0.12.10 → 0.12.11 |
|
|
13
|
+
| **Minor** (0.X.0) | New tools, new features, new config options | 0.12.11 → 0.13.0 |
|
|
14
|
+
| **Major** (X.0.0) | Breaking API changes (not used yet) | 0.13.0 → 1.0.0 |
|
|
15
|
+
|
|
16
|
+
## Version Bump Locations
|
|
17
|
+
|
|
18
|
+
All three files must match the same version string:
|
|
19
|
+
|
|
20
|
+
| File | Field |
|
|
21
|
+
|------|-------|
|
|
22
|
+
| `package.json` | `"version": "X.Y.Z"` |
|
|
23
|
+
| `openclaw.plugin.json` | `"version": "X.Y.Z"` and description string |
|
|
24
|
+
| `index.ts` | Header comment `Version: X.Y.Z` |
|
|
25
|
+
|
|
26
|
+
## CHANGELOG.md Format
|
|
27
|
+
|
|
28
|
+
Follows [Keep a Changelog](https://keepachangelog.com/). Each release entry:
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
## [X.Y.Z] - YYYY-MM-DD
|
|
32
|
+
### Added
|
|
33
|
+
- **Feature Name**: Description
|
|
34
|
+
### Changed
|
|
35
|
+
- Description
|
|
36
|
+
### Fixed
|
|
37
|
+
- **Bug Name**: Description
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Add a comparison link at the bottom of the file:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
[X.Y.Z]: https://github.com/memoryrelay/openclaw-plugin/compare/vPREV...vX.Y.Z
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Git Commit Conventions
|
|
47
|
+
|
|
48
|
+
| Prefix | Use |
|
|
49
|
+
|--------|-----|
|
|
50
|
+
| `feat:` | New features or tools |
|
|
51
|
+
| `fix:` | Bug fixes |
|
|
52
|
+
| `docs:` | Documentation changes |
|
|
53
|
+
| `chore:` | Maintenance, deps, cleanup |
|
|
54
|
+
|
|
55
|
+
## CI/CD Workflows
|
|
56
|
+
|
|
57
|
+
| File | Trigger | Purpose |
|
|
58
|
+
|------|---------|---------|
|
|
59
|
+
| `.github/workflows/ci.yml` | Push/PR to main | Tests on Node 20.x + 22.x matrix |
|
|
60
|
+
| `.github/workflows/ci-cd.yml` | Push/PR | Full CI/CD pipeline |
|
|
61
|
+
| `.github/workflows/publish.yml` | Manual dispatch | NPM publish with version verification |
|
|
62
|
+
|
|
63
|
+
The publish workflow runs `npm publish --provenance --access public` and requires the `NPM_TOKEN` secret.
|
|
64
|
+
|
|
65
|
+
## Pre-Release Audit Branch
|
|
66
|
+
|
|
67
|
+
For doc review before release, create an audit branch:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
docs/pre-release-audit-v{version}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Example: `docs/pre-release-audit-v0.12.11`. Merge to main once the audit is complete.
|
|
74
|
+
|
|
75
|
+
## Release Checklist
|
|
76
|
+
|
|
77
|
+
1. Update version in all 3 locations (`package.json`, `openclaw.plugin.json`, `index.ts`)
|
|
78
|
+
2. Update `CHANGELOG.md` with new entry and comparison link
|
|
79
|
+
3. Run `npm test` -- all tests must pass
|
|
80
|
+
4. Create audit branch (`docs/pre-release-audit-v{version}`) if doc changes are needed
|
|
81
|
+
5. Merge audit branch to main
|
|
82
|
+
6. Trigger the `publish.yml` workflow manually from GitHub Actions
|
|
83
|
+
7. Verify the published package on NPM
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-memoryrelay
|
|
3
|
+
description: "Use when writing, running, or debugging tests for the MemoryRelay plugin, adding test coverage for new tools or hooks, or investigating test failures."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing MemoryRelay
|
|
7
|
+
|
|
8
|
+
Test runner: **Vitest**. All tests run without a live API.
|
|
9
|
+
|
|
10
|
+
## Commands
|
|
11
|
+
|
|
12
|
+
| Command | Purpose |
|
|
13
|
+
|---------|---------|
|
|
14
|
+
| `npm test` | Run all tests once (`vitest run`) |
|
|
15
|
+
| `npm run test:watch` | Watch mode (`vitest`) |
|
|
16
|
+
| `npm run test:coverage` | Coverage report (`vitest run --coverage`) |
|
|
17
|
+
|
|
18
|
+
## Test Files
|
|
19
|
+
|
|
20
|
+
| File | Scope |
|
|
21
|
+
|------|-------|
|
|
22
|
+
| `index.test.ts` | Integration tests: API client, tools, hooks, retry logic, pattern detection, channel filtering, tool groups, workflow instructions |
|
|
23
|
+
| `src/debug-logger.test.ts` | DebugLogger unit tests: circular buffer, filtering by tool/status, stats, formatting |
|
|
24
|
+
| `src/status-reporter.test.ts` | StatusReporter unit tests: failure tracking, report building, formatting |
|
|
25
|
+
|
|
26
|
+
## Mock Pattern
|
|
27
|
+
|
|
28
|
+
Tests use `MockMemoryRelayClient` -- an in-memory implementation that replaces the real API client:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { describe, test, expect, beforeEach, vi } from "vitest";
|
|
32
|
+
|
|
33
|
+
class MockMemoryRelayClient {
|
|
34
|
+
private memories: Memory[] = [];
|
|
35
|
+
private nextId = 1;
|
|
36
|
+
async store(content, metadata?) { /* push to array, return Memory */ }
|
|
37
|
+
async search(query, limit?, threshold?) { /* keyword .includes() match */ }
|
|
38
|
+
async list(limit?, offset?) { /* .slice() */ }
|
|
39
|
+
async get(id) { /* .find(), throws if missing */ }
|
|
40
|
+
async delete(id) { /* .splice(), throws if missing */ }
|
|
41
|
+
async health() { return { status: "healthy" }; }
|
|
42
|
+
async stats() { return { total_memories: this.memories.length }; }
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Instantiate fresh per test with `beforeEach(() => { client = new MockMemoryRelayClient("test_key", "test_agent"); })`.
|
|
47
|
+
|
|
48
|
+
## What to Test per Tool
|
|
49
|
+
|
|
50
|
+
| Area | Checks |
|
|
51
|
+
|------|--------|
|
|
52
|
+
| Input validation | Required params present, types correct |
|
|
53
|
+
| Success path | API response formatted correctly, data stored/returned |
|
|
54
|
+
| Error handling | Non-existent IDs throw, empty results return `[]` |
|
|
55
|
+
| Deduplication | `deduplicate=true` prevents near-duplicate storage |
|
|
56
|
+
| Session injection | `session_id` auto-applied from active session |
|
|
57
|
+
| Retry logic | Network errors and 5xx retried; 4xx not retried |
|
|
58
|
+
| Timeouts | 30s timeout via `AbortController` |
|
|
59
|
+
|
|
60
|
+
## Testing Hooks
|
|
61
|
+
|
|
62
|
+
**`before_agent_start`** -- workflow injection and auto-recall:
|
|
63
|
+
|
|
64
|
+
- Verify workflow instructions are built from enabled tool groups
|
|
65
|
+
- Mock `client.search()` to test auto-recall injects context
|
|
66
|
+
- Test channel exclusion skips auto-recall for blocklisted channels
|
|
67
|
+
|
|
68
|
+
**`agent_end`** -- auto-capture:
|
|
69
|
+
|
|
70
|
+
- Test pattern detection (`shouldCapture`) with regex matching
|
|
71
|
+
- Verify length bounds (20-2000 chars)
|
|
72
|
+
- Confirm privacy blocklist rejects passwords, SSNs, API keys
|
|
73
|
+
- Test tier logic: `off`, `conservative`, `smart`, `aggressive`
|
|
74
|
+
|
|
75
|
+
## Testing Gateway Methods
|
|
76
|
+
|
|
77
|
+
| Check | How |
|
|
78
|
+
|-------|-----|
|
|
79
|
+
| Response format | Assert returned object shape matches API contract |
|
|
80
|
+
| Error surfaces | `detail` field extracted (FastAPI format), falls back to `message` |
|
|
81
|
+
| HTTP method | GET with query params for search/check; POST with body for create/link |
|
|
82
|
+
|
|
83
|
+
## Unit Test Patterns
|
|
84
|
+
|
|
85
|
+
**DebugLogger**: Uses `vi.mock("fs")`. Test circular buffer (`maxEntries`), `getRecentLogs(n)`, `getToolLogs(name)`, `getErrorLogs()`, `getStats()`, `clear()`, `formatEntry()`.
|
|
86
|
+
|
|
87
|
+
**StatusReporter**: Instantiate with real `DebugLogger`. Test `recordFailure`/`recordSuccess` toggle, `buildReport` shape, `formatReport`/`formatCompact` output, disconnected status handling.
|