Project: Project AI Chatbot Memstore Version: 1.1.0 Date: 2026-10-26 Another collaboration between Andrew.human and Claude.ai
Written to be read by people and by AI models.
A small personal memory store in one Python file, backed by one SQLite file. It holds short statements about the operator (one entry per statement), each with the quote it came from. It runs without any language model on the machine.
The rule it enforces: nothing becomes live memory unless the operator adds it or approves it. Only approved entries are ever printed by inject.
A separate program, qwen_propose.py (see QWEN_PROPOSE_MANUAL.md), can suggest entries using a local model. It never touches this database.
sqlite3 module. No other packages.Copy the new memstore.py over the old one and run any command. The first run adds three columns (kind, importance, superseded_by) to your existing database automatically. Existing entries become kind fact, importance 2. Back up memstore.db first if you want a way back; the 1.0.0 program cannot read a migrated database's new columns but will still open it.
Default /root/memstore/memstore.db (the folder comes from $MEMDIR if set), whatever folder you run the command from. Override with --db PATH or the environment variable MEMSTORE_DB. Created on first run. The path in use prints to stderr on every run.
Each entry holds:
| Field | Meaning |
|---|---|
id |
Entry number |
text |
The statement, short, third person preferred ("Operator prefers X") |
quote |
The original words it came from |
source_id |
Which transcript or conversation it came from (optional) |
origin |
stated (said directly) or inferred (concluded, not said) |
kind |
fact, or correction (always injected) |
importance |
1 to 3, default 2; ranks inject output |
status |
proposed, approved, rejected or superseded |
superseded_by |
Id of the entry that replaced this one |
sensitive |
1 if a sensitive keyword matched the text or the quote |
created, decided |
UTC timestamps |
Every run prints memstore 1.1.0 (2026-10-26) once to stderr at start, so inject output on stdout stays clean for piping.
| Command | What it does |
|---|---|
add TEXT... [--quote Q] [--source S] [--kind fact|correction] [--importance 1-3] |
Explicit entry. Approved immediately, origin stated. Refused only if the same text is already proposed or approved. |
supersede OLD_ID TEXT... [--quote Q] [--source S] [--kind K] [--importance N] |
Replace an approved entry. The new entry is approved at once. The old one is kept, marked superseded, and never injected. Kind and importance default to the old entry's. |
propose FILE.json |
Import candidates. Status proposed. Nothing is live yet. |
review |
Show everything awaiting approval, with quote and flags. |
approve ID... [--importance N] |
Approve specific entries, optionally setting importance. |
approve --all |
Approve all proposals except sensitive ones, which are listed as held back. |
reject ID... |
Reject proposals. Kept as rejected so they are not re-proposed. |
list [--status S] |
List entries. Each line shows id, status, importance, flags. |
inject [WORDS...] [--limit N] |
Print approved entries as - text lines (see below). |
forget --id N |
Delete one entry for real. |
forget --source S |
Delete every entry that came from source S. |
inject orders its output- CORRECTION: text. They are never filtered by keywords and never count against --limit.--limit N caps the facts only.[inferred] suffix. Superseded, rejected and proposed entries are never printed.supersede keeps history: the old text stays in the database, visible in list. forget is real deletion (the row is removed, secure_delete is on, and the file is compacted with VACUUM). Use forget when text must not remain, including old superseded entries.
A JSON list. Each item:
[
{
"text": "Operator prefers short replies",
"quote": "keep it short please",
"source_id": "chat-2026-10-25-01",
"origin": "stated",
"kind": "fact",
"importance": 2
}
]
text and quote are required. An item with no quote is rejected, because every entry must be checkable.origin defaults to inferred. kind defaults to fact. importance defaults to 2 and must be 1 to 3.propose exits with status 1 if any item was invalid, after importing the valid ones.On import (and on add), an entry is flagged SENSITIVE if its text or its quote matches keywords for health, identity and belief, money and legal matters. Flagged entries are never approved by approve --all; each needs approve ID.
Limits, stated plainly:
add are flagged but approved anyway, because the operator typed them.python3 memstore.py add "Operator prefers Markdown" --quote "Markdown only"
python3 memstore.py add "Operator requires ordered shutdowns" --kind correction --importance 3
python3 memstore.py propose proposals.json
python3 memstore.py review
python3 memstore.py approve 4 7
python3 memstore.py approve --all
python3 memstore.py supersede 3 "Operator runs CentOS 6.10" --quote "6.10"
python3 memstore.py inject markdown --limit 20
python3 memstore.py forget --source chat-2026-10-25-01
0 success, 1 import finished with invalid items, 2 usage or input error.
No service or background process is involved. The program starts, runs one command and exits.
| Version | Date | Change |
|---|---|---|
| 1.1.1 | 2026-10-27 | Database default is now /root/memstore/memstore.db instead of ./memstore.db; the path in use prints at start. |
| 1.1.0 | 2026-10-26 | Added correction kind, supersede, importance ranking, automatic migration. Fixed: rejected/superseded entries could be re-proposed; sensitive check ignored the quote; inject --limit kept the oldest entries. |
| 1.0.0 | 2026-10-25 | First release. |