@hilbras/remembra 0.1.0 → 0.3.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/CHANGELOG.md +31 -0
- package/README.md +29 -4
- package/dist/embeddings.d.ts +12 -0
- package/dist/embeddings.js +65 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/http.d.ts +19 -0
- package/dist/http.js +114 -0
- package/dist/http.js.map +1 -0
- package/dist/index.js +98 -75
- package/dist/index.js.map +1 -1
- package/dist/llm.d.ts +21 -0
- package/dist/llm.js +142 -0
- package/dist/llm.js.map +1 -0
- package/dist/retrieval.d.ts +11 -6
- package/dist/retrieval.js +57 -25
- package/dist/retrieval.js.map +1 -1
- package/dist/service.d.ts +64 -0
- package/dist/service.js +121 -0
- package/dist/service.js.map +1 -0
- package/dist/store.d.ts +1 -1
- package/dist/store.js +10 -1
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.js.map +1 -1
- package/docs/chatgpt.md +200 -0
- package/docs/clients.md +13 -2
- package/docs/providers.md +107 -0
- package/docs/tools.md +16 -2
- package/package.json +1 -1
package/docs/chatgpt.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# ChatGPT Setup (v1.5)
|
|
2
|
+
|
|
3
|
+
ChatGPT doesn't speak MCP, so Remembra exposes the same memory handlers over a plain
|
|
4
|
+
HTTP API. You connect it by creating a **Custom GPT** with API actions.
|
|
5
|
+
|
|
6
|
+
## 1. Start the HTTP server
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
export REMEMBRA_API_KEY="pick-a-long-random-secret"
|
|
10
|
+
remembra --http --port 8787
|
|
11
|
+
# or, from source:
|
|
12
|
+
node dist/index.js --http --port 8787
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Check it's up:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
curl http://localhost:8787/health
|
|
19
|
+
# {"status": "ok"}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- `REMEMBRA_API_KEY` **strongly recommended** — without it every endpoint is open.
|
|
23
|
+
- The server binds to localhost by default. For ChatGPT to reach it you must expose it
|
|
24
|
+
publicly (see [§4](#4-exposing-the-server)).
|
|
25
|
+
|
|
26
|
+
## 2. HTTP API reference
|
|
27
|
+
|
|
28
|
+
All endpoints except `/health` require the key via `x-api-key` or `Authorization: Bearer`.
|
|
29
|
+
|
|
30
|
+
### Store a memory
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
curl -X POST http://localhost:8787/memories \
|
|
34
|
+
-H "content-type: application/json" \
|
|
35
|
+
-H "x-api-key: $REMEMBRA_API_KEY" \
|
|
36
|
+
-d '{
|
|
37
|
+
"type": "decision",
|
|
38
|
+
"content": "Chose monthly billing over annual",
|
|
39
|
+
"scope": "global",
|
|
40
|
+
"tags": ["pricing"],
|
|
41
|
+
"importance": 4
|
|
42
|
+
}'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Search memories
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
curl "http://localhost:8787/memories/search?query=billing&scope=global&limit=5" \
|
|
49
|
+
-H "x-api-key: $REMEMBRA_API_KEY"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Query param | Description |
|
|
53
|
+
|-------------|-------------|
|
|
54
|
+
| `query` (or `q`) | keywords to match |
|
|
55
|
+
| `scope` | project/workspace filter |
|
|
56
|
+
| `type` | `fact` \| `decision` \| `role` \| `history` |
|
|
57
|
+
| `limit` | max results (default 10) |
|
|
58
|
+
|
|
59
|
+
### List memories
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
curl "http://localhost:8787/memories?scope=global&type=role" \
|
|
63
|
+
-H "x-api-key: $REMEMBRA_API_KEY"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Delete a memory
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
curl -X DELETE http://localhost:8787/memories/<id> \
|
|
70
|
+
-H "x-api-key: $REMEMBRA_API_KEY"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Digest a session (LLM extraction)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
curl -X POST http://localhost:8787/memories/digest \
|
|
77
|
+
-H "content-type: application/json" \
|
|
78
|
+
-H "x-api-key: $REMEMBRA_API_KEY" \
|
|
79
|
+
-d '{"transcript":"<conversation text>","scope":"chatgpt"}'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Requires `REMEMBRA_LLM` + key — see [providers.md](providers.md).
|
|
83
|
+
|
|
84
|
+
## 3. Create the Custom GPT
|
|
85
|
+
|
|
86
|
+
1. Go to **chatgpt.com → Explore GPTs → Create a GPT**.
|
|
87
|
+
2. **Name**: Remembra (or whatever you like).
|
|
88
|
+
3. **Instructions** — paste this:
|
|
89
|
+
|
|
90
|
+
> You have long-term memory powered by Remembra. At the start of every conversation,
|
|
91
|
+
> call `search_memories` with no query to load your roles, facts and decisions.
|
|
92
|
+
> Whenever the user tells you something worth remembering (a fact, a decision,
|
|
93
|
+
> their role or preferences) or a decision is made, call `store_memory`.
|
|
94
|
+
> Scope for this chat is `chatgpt` unless the user is discussing a specific project.
|
|
95
|
+
> If the model asks you to forget something, call `delete_memory` with its id.
|
|
96
|
+
|
|
97
|
+
4. **Capabilities** → enable **Actions**.
|
|
98
|
+
5. Under **Actions → Create new action**, paste this schema (fill in your domain and key):
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"openapi": "3.1.0",
|
|
103
|
+
"info": { "title": "Remembra Memory", "version": "1.0.0" },
|
|
104
|
+
"servers": [{ "url": "https://YOUR-DOMAIN.example" }],
|
|
105
|
+
"paths": {
|
|
106
|
+
"/memories": {
|
|
107
|
+
"post": {
|
|
108
|
+
"operationId": "store_memory",
|
|
109
|
+
"summary": "Store a fact, decision, role or history",
|
|
110
|
+
"requestBody": {
|
|
111
|
+
"required": true,
|
|
112
|
+
"content": {
|
|
113
|
+
"application/json": {
|
|
114
|
+
"schema": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"required": ["type", "content"],
|
|
117
|
+
"properties": {
|
|
118
|
+
"type": { "type": "string", "enum": ["fact", "decision", "role", "history"] },
|
|
119
|
+
"content": { "type": "string", "description": "Standalone statement" },
|
|
120
|
+
"scope": { "type": "string", "default": "global" },
|
|
121
|
+
"tags": { "type": "array", "items": { "type": "string" } },
|
|
122
|
+
"importance": { "type": "integer", "minimum": 1, "maximum": 5 }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"responses": { "201": { "description": "Stored" } }
|
|
129
|
+
},
|
|
130
|
+
"get": {
|
|
131
|
+
"operationId": "list_memories",
|
|
132
|
+
"summary": "List stored memories",
|
|
133
|
+
"parameters": [
|
|
134
|
+
{ "name": "scope", "in": "query", "schema": { "type": "string" } },
|
|
135
|
+
{ "name": "type", "in": "query", "schema": { "type": "string" } }
|
|
136
|
+
],
|
|
137
|
+
"responses": { "200": { "description": "OK" } }
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"/memories/search": {
|
|
141
|
+
"get": {
|
|
142
|
+
"operationId": "search_memories",
|
|
143
|
+
"summary": "Search memories",
|
|
144
|
+
"parameters": [
|
|
145
|
+
{ "name": "query", "in": "query", "schema": { "type": "string" } },
|
|
146
|
+
{ "name": "scope", "in": "query", "schema": { "type": "string" } },
|
|
147
|
+
{ "name": "type", "in": "query", "schema": { "type": "string" } },
|
|
148
|
+
{ "name": "limit", "in": "query", "schema": { "type": "integer" } }
|
|
149
|
+
],
|
|
150
|
+
"responses": { "200": { "description": "OK" } }
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"/memories/{id}": {
|
|
154
|
+
"delete": {
|
|
155
|
+
"operationId": "delete_memory",
|
|
156
|
+
"summary": "Delete a memory by id",
|
|
157
|
+
"parameters": [
|
|
158
|
+
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
159
|
+
],
|
|
160
|
+
"responses": { "200": { "description": "Deleted" } }
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"components": {
|
|
165
|
+
"securitySchemes": {
|
|
166
|
+
"apiKeyAuth": { "type": "apiKey", "in": "header", "name": "x-api-key" }
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"security": [{ "apiKeyAuth": [] }]
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
6. In **Authentication**, choose **API Key → Custom → Header → `x-api-key`**, and paste
|
|
174
|
+
your `REMEMBRA_API_KEY`.
|
|
175
|
+
7. **Save** (Only me / Anyone, your choice) and test:
|
|
176
|
+
|
|
177
|
+
> *"Remember that I prefer metric units."* → the GPT should call `store_memory`.
|
|
178
|
+
> Then in a **new chat**: *"What units do I prefer?"* → it calls `search_memories`
|
|
179
|
+
> and answers. That's the whole point of Remembra — the memory survived the
|
|
180
|
+
> context reset.
|
|
181
|
+
|
|
182
|
+
## 4. Exposing the server
|
|
183
|
+
|
|
184
|
+
ChatGPT must reach your server over HTTPS. Options, easiest first:
|
|
185
|
+
|
|
186
|
+
| Approach | Notes |
|
|
187
|
+
|----------|-------|
|
|
188
|
+
| **Cloud VM / VPS** | Run `remembra --http` behind nginx/Caddy with TLS. Simplest for a personal server. |
|
|
189
|
+
| **Tunnel** | `cloudflared tunnel` or `ngrok http 8787` — quick HTTPS URL for testing. |
|
|
190
|
+
| **Serverless** | Port `service.ts` handlers to a Lambda/Cloudflare Worker (v2 territory). |
|
|
191
|
+
|
|
192
|
+
> ⚠️ Always set `REMEMBRA_API_KEY` when the server is reachable from the internet,
|
|
193
|
+
> and prefer a tunnel with access restrictions while testing.
|
|
194
|
+
|
|
195
|
+
## 5. Sharing memory with your coding tools
|
|
196
|
+
|
|
197
|
+
Because both transports use the same storage (`~/.remembra`), memories written by
|
|
198
|
+
ChatGPT appear in OpenCode/Claude Code and vice versa — just point both at the same
|
|
199
|
+
`REMEMBRA_HOME`. Use scope `chatgpt` for chat-specific memories and `global` for
|
|
200
|
+
anything that should follow you everywhere.
|
package/docs/clients.md
CHANGED
|
@@ -71,14 +71,25 @@ Add to the MCP config file used by Kimi CLI:
|
|
|
71
71
|
|
|
72
72
|
## ChatGPT
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
Custom GPT action
|
|
74
|
+
Uses the HTTP mode instead of MCP — see the full walkthrough in
|
|
75
|
+
**[chatgpt.md](chatgpt.md)** (server start, API reference, Custom GPT action schema,
|
|
76
|
+
tunneling options).
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
REMEMBRA_API_KEY="your-secret" remembra --http
|
|
80
|
+
```
|
|
76
81
|
|
|
77
82
|
## Environment
|
|
78
83
|
|
|
79
84
|
| Variable | Default | Purpose |
|
|
80
85
|
|----------|---------|---------|
|
|
81
86
|
| `REMEMBRA_HOME` | `~/.remembra` | Where memory files live |
|
|
87
|
+
| `REMEMBRA_API_KEY` | *(unset)* | Enables auth on the HTTP API |
|
|
88
|
+
| `REMEMBRA_PORT` | `8787` | HTTP API port (`--port` overrides) |
|
|
89
|
+
| `REMEMBRA_LLM` | `openai` | Digest LLM: `openai` \| `anthropic` \| `ollama` |
|
|
90
|
+
| `REMEMBRA_EMBEDDINGS` | `none` | Semantic search: `openai` \| `ollama` \| `none` |
|
|
91
|
+
|
|
92
|
+
LLM/embedding key setup: see **[providers.md](providers.md)**.
|
|
82
93
|
|
|
83
94
|
## Tips
|
|
84
95
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# AI Providers & Session Digest (v2)
|
|
2
|
+
|
|
3
|
+
Remembra can call an LLM to extract memories automatically (**session digest**)
|
|
4
|
+
and use embeddings for semantic search. Both are pluggable and off-by-default
|
|
5
|
+
where possible, so a plain keyword install still works with zero API keys.
|
|
6
|
+
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
| Variable | Values | Default | Purpose |
|
|
10
|
+
|----------|--------|---------|---------|
|
|
11
|
+
| `REMEMBRA_LLM` | `openai` \| `anthropic` \| `ollama` | `openai` | Which LLM does digest extraction |
|
|
12
|
+
| `REMEMBRA_LLM_MODEL` | provider model id | provider default | Override the extraction model |
|
|
13
|
+
| `REMEMBRA_EMBEDDINGS` | `openai` \| `ollama` \| `none` | `none` | Semantic search provider |
|
|
14
|
+
| `REMEMBRA_EMBEDDING_MODEL` | provider model id | provider default | Override the embedding model |
|
|
15
|
+
| `OPENAI_API_KEY` | — | — | Required when provider = openai |
|
|
16
|
+
| `ANTHROPIC_API_KEY` | — | — | Required when provider = anthropic |
|
|
17
|
+
| `OLLAMA_HOST` | URL | `http://localhost:11434` | Ollama endpoint (LLM and/or embeddings) |
|
|
18
|
+
|
|
19
|
+
### Examples
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# OpenAI for both (simplest hosted setup)
|
|
23
|
+
export OPENAI_API_KEY=sk-...
|
|
24
|
+
export REMEMBRA_LLM=openai
|
|
25
|
+
export REMEMBRA_EMBEDDINGS=openai
|
|
26
|
+
|
|
27
|
+
# Fully local with Ollama — no API keys
|
|
28
|
+
export REMEMBRA_LLM=ollama
|
|
29
|
+
export REMEMBRA_LLM_MODEL=llama3.2
|
|
30
|
+
export REMEMBRA_EMBEDDINGS=ollama
|
|
31
|
+
export REMEMBRA_EMBEDDING_MODEL=nomic-embed-text
|
|
32
|
+
|
|
33
|
+
# Anthropic for extraction, semantic search off (keyword mode)
|
|
34
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
35
|
+
export REMEMBRA_LLM=anthropic
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Session digest
|
|
39
|
+
|
|
40
|
+
Instead of the model remembering to call `memory_store` for every little thing,
|
|
41
|
+
hand the whole conversation to one tool at the end of a session:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
memory_digest {
|
|
45
|
+
transcript: "<full transcript or a detailed summary>",
|
|
46
|
+
scope: "/path/to/project", // optional, default global
|
|
47
|
+
source: "opencode" // optional
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Remembra asks the configured LLM to extract **facts, decisions, roles, and
|
|
52
|
+
history**, then stores each one — **skipping exact duplicates** that are
|
|
53
|
+
already present (normalized by type + scope + content). Running a digest twice
|
|
54
|
+
over the same conversation is a no-op.
|
|
55
|
+
|
|
56
|
+
HTTP equivalent:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
curl -X POST http://localhost:8787/memories/digest \
|
|
60
|
+
-H "content-type: application/json" \
|
|
61
|
+
-H "x-api-key: $REMEMBRA_API_KEY" \
|
|
62
|
+
-d '{"transcript":"...","scope":"chatgpt","source":"chatgpt"}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Response:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"extracted": 4,
|
|
70
|
+
"stored": [ ... ],
|
|
71
|
+
"skippedDuplicates": 2,
|
|
72
|
+
"ids": ["a1b2c3d4", "..."]
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> **Note:** the digest LLM key is only needed when you actually call
|
|
77
|
+
> `memory_digest` — storage and search work without it.
|
|
78
|
+
|
|
79
|
+
## Semantic search
|
|
80
|
+
|
|
81
|
+
With `REMEMBRA_EMBEDDINGS=openai|ollama`:
|
|
82
|
+
|
|
83
|
+
- **On write**: every stored memory gets an embedding, cached in its
|
|
84
|
+
frontmatter (`embedding: [...]`) — computed once, never re-embedded.
|
|
85
|
+
- **On search**: the query is embedded and **cosine similarity becomes the
|
|
86
|
+
primary ranking signal**. Importance and recency remain small modifiers.
|
|
87
|
+
- **Gates stay absolute**: `role` memories always surface, and memories from
|
|
88
|
+
other scopes are never returned, no matter how similar.
|
|
89
|
+
- **Memories without vectors** (stored while embeddings were off) fall back
|
|
90
|
+
to keyword matching.
|
|
91
|
+
|
|
92
|
+
With `REMEMBRA_EMBEDDINGS=none` (default): pure keyword scoring — exactly
|
|
93
|
+
the v1 behavior.
|
|
94
|
+
|
|
95
|
+
### Backfilling vectors
|
|
96
|
+
|
|
97
|
+
Memories stored before you enabled embeddings have no vectors. They still
|
|
98
|
+
work (keyword fallback), but to bring them into semantic search, re-store
|
|
99
|
+
them or wait for v3's maintenance commands.
|
|
100
|
+
|
|
101
|
+
## Failure behavior
|
|
102
|
+
|
|
103
|
+
- **Embedding API fails** → warning logged, write continues without a vector,
|
|
104
|
+
search degrades to keywords. Never blocks storing.
|
|
105
|
+
- **LLM call fails** → `memory_digest` returns the error; nothing is stored.
|
|
106
|
+
- **No keys configured** → MCP/HTTP servers run normally; only `memory_digest`
|
|
107
|
+
errors if invoked.
|
package/docs/tools.md
CHANGED
|
@@ -64,12 +64,26 @@ Permanently delete a memory.
|
|
|
64
64
|
|
|
65
65
|
Returns an error result if no memory matches the id.
|
|
66
66
|
|
|
67
|
+
## `memory_digest`
|
|
68
|
+
|
|
69
|
+
Extract memories from a conversation transcript using the configured LLM and
|
|
70
|
+
store them, skipping exact duplicates. See [providers.md](providers.md).
|
|
71
|
+
|
|
72
|
+
| Argument | Type | Required | Description |
|
|
73
|
+
|----------|------|----------|-------------|
|
|
74
|
+
| `transcript` | string | ✅ | Full transcript or a detailed session summary |
|
|
75
|
+
| `scope` | string | no | Scope for extracted memories (default `global`) |
|
|
76
|
+
| `source` | string | no | Originating session/client |
|
|
77
|
+
|
|
78
|
+
Requires `REMEMBRA_LLM` + its API key (or Ollama). Returns counts:
|
|
79
|
+
extracted / stored / duplicates skipped, plus stored ids.
|
|
80
|
+
|
|
67
81
|
---
|
|
68
82
|
|
|
69
83
|
## Suggested session flow
|
|
70
84
|
|
|
71
85
|
```
|
|
72
|
-
1. memory_search { scope: <current project> }
|
|
86
|
+
1. memory_search { scope: <current project> } → recover roles, facts, decisions
|
|
73
87
|
2. ... work happens; model calls memory_store when something worth keeping emerges ...
|
|
74
|
-
3.
|
|
88
|
+
3. memory_digest { transcript, scope } → end-of-session sweep (v2, LLM extracts)
|
|
75
89
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hilbras/remembra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "External memory for AI assistants — remember facts, decisions, roles and history across sessions. MCP server for OpenCode, Claude Code, Cline, Kimi Code and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|