mnestome — the emergent graph of all mnestsThis document defines the mnestome: the data structure that holds the set of all active mnests and governs their lifecycle. It is the third of three canonical docs introduced by the Dialogue on executors and distributed memory (24 April 2026), and it is a new concept: the previous microdesign did not have it. Technically it is a weighted directed graph persisted in SQLite; ontologically it is Metnos's relational memory — what it remembers having done together.
The document covers:
It does not cover, and defers to other docs:
The mnestome is a weighted directed graph in which:
The mnestome emerges. No one designs it a priori: it is born empty at first boot and forms turn after turn, while the gateway observes which executors pass output to which others. The shapes it takes reflect how the system is used: an «invoice archiving» user's mnestome has different clusters than a «daily news roundup» user's, even when the seed of executors is the same.
The word «memory» in an AI agent has too many meanings. It is worth saying clearly what the mnestome is not:
| What the mnestome is NOT | Where that concept lives, then |
|---|---|
| The LLM's conversational memory (recent turns, in-token context). | In the working memory of the execution trace, see memory.html (in Italian and pending rewrite). |
| The episodic memory of past conversations (what Roberto said yesterday). | In the episodic memory, indexed by sender. See memory.html. |
| The semantic memory of facts about Roberto and his world («the dog's name is Fido»). | In the semantic memory, extracted via reflection and approved by the user. |
| The audit log of completed actions. | In workspace/.audit/, append-only, JSONL. |
| The user's file workspace (notes, invoices, photos). | In workspace/, managed separately. |
| The definition of capabilities (the individual executors). | In workspace/executors/, file by file. |
The mnestome is the observed relation between executors: who worked with whom, how often, how recently. Nothing more.
The mnestome lives in workspace/.mnestome/mnest.sqlite, a
single SQLite file. The choice of SQLite is deliberate: zero services
to start, zero external dependencies, trivial backup (file copy),
proven reliability.
executors
A lightweight replica of the manifest, in fast-read mode for gateway
queries. The canonical manifest always remains
workspace/executors/<name>/manifest.toml; this table
is an index.
CREATE TABLE executors (
name TEXT NOT NULL,
version TEXT NOT NULL,
state TEXT NOT NULL, -- seed | active | quarantine | archived
loaded_at TEXT NOT NULL, -- ISO 8601
manifest_hash TEXT NOT NULL, -- blake3
PRIMARY KEY (name, version)
);
CREATE INDEX idx_executors_state ON executors(state);
mnestsCREATE TABLE mnests (
id TEXT PRIMARY KEY, -- ULID
src_executor TEXT NOT NULL,
src_version TEXT NOT NULL,
dst_executor TEXT NOT NULL, -- canonical name OR desired name (proto)
dst_version TEXT, -- NULL for proto
weight REAL NOT NULL CHECK (weight BETWEEN 0 AND 1),
uses INTEGER NOT NULL CHECK (uses >= 1),
ts_first TEXT NOT NULL,
ts_last TEXT NOT NULL,
decay_lambda REAL NOT NULL DEFAULT 0.018,
state TEXT NOT NULL, -- proto | active | decaying | superseded
tags TEXT, -- JSON array
desired_sig TEXT, -- JSON, only for proto
CHECK (ts_last >= ts_first),
UNIQUE (src_executor, src_version, dst_executor, dst_version, state)
);
CREATE INDEX idx_mnests_dst ON mnests(dst_executor);
CREATE INDEX idx_mnests_src ON mnests(src_executor);
CREATE INDEX idx_mnests_weight ON mnests(weight DESC);
CREATE INDEX idx_mnests_state ON mnests(state);
eventsAppend-only, records every reinforcement or decay applied. Allows the weight trajectory of a mnest to be reconstructed and to be recomputed later if the formula changes.
CREATE TABLE events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mnest_id TEXT NOT NULL,
ts TEXT NOT NULL,
kind TEXT NOT NULL, -- reinforce | decay | state_change
delta REAL, -- weight delta (NULL for state_change)
new_state TEXT, -- only for state_change
reason TEXT, -- e.g. "ager nightly", "synt approved"
FOREIGN KEY (mnest_id) REFERENCES mnests(id)
);
CREATE INDEX idx_events_mnest ON events(mnest_id);
CREATE INDEX idx_events_ts ON events(ts);
v_mnestome
The «live» graph for read queries. Excludes
superseded and shows active + proto:
CREATE VIEW v_mnestome AS
SELECT id, src_executor, src_version, dst_executor, dst_version,
weight, uses, ts_last, state, tags, desired_sig
FROM mnests
WHERE state IN ('active', 'proto');
record_passingThe only write operation during a turn. Atomic per pair. Pseudocode:
def record_passing(src, dst, turn_ctx) -> mnest_id:
with conn.transaction():
if dst.exists:
row = SELECT * FROM mnests
WHERE src_executor = src.name AND src_version = src.version
AND dst_executor = dst.name AND dst_version = dst.version
AND state = 'active'
if row:
w = decay(row.weight, now() - row.ts_last, row.decay_lambda) + REINFORCE_DELTA
UPDATE mnests SET weight = clamp01(w), uses = uses + 1, ts_last = now()
INSERT INTO events (mnest_id, ts, kind, delta, reason)
VALUES (row.id, now(), 'reinforce', REINFORCE_DELTA, turn_ctx.id)
return row.id
else:
id = ulid()
INSERT INTO mnests (id, src_*, dst_*, weight, uses, ts_first, ts_last, state, tags)
VALUES (id, ..., BOOTSTRAP_WEIGHT, 1, now(), now(), 'active', tags)
INSERT INTO events (mnest_id, ts, kind, delta, reason)
VALUES (id, now(), 'reinforce', BOOTSTRAP_WEIGHT, turn_ctx.id)
return id
else:
# proto-mnest
id = ulid()
desired = build_desired_signature(turn_ctx)
INSERT INTO mnests (..., dst_executor=dst.desired_name, dst_version=NULL,
..., state='proto', desired_sig=desired)
return id
| Query | Use |
|---|---|
top_k_outgoing(executor, k) | Given an executor, returns the k heaviest outgoing mnests. |
top_k_incoming(executor, k) | Given an executor, returns the k heaviest incoming mnests. |
walk(start, max_depth) | Weighted BFS from the starting node, up to a maximum depth. Used by the gateway to build the execution context. |
recurring_protos(min_uses, since) | List of proto-mnests that have crossed a recurrence threshold. Trigger of the synt. |
by_tag(tag) | All mnests with a given tag. Used by observability and the ager for clustering. |
decaying() | Mnests in decaying state. Used by the ager for archival proposals. |
State transitions are made by specific components (ager, synt, gateway
in case of executor quarantine). All are accompanied by an
events row with kind = 'state_change' and a
mandatory reason; this is the principle of reversibility
(ch. 14 of the Architecture): you do not change state without a trace
of the why.
The ager is the process that applies decay and signals the state transitions that pure time requires. It runs once a day, in a night window (default: 04:00 local time), in a long but low-impact transaction:
active mnest, compute weight_new = weight_old · exp(-λ · Δt) where Δt is the time elapsed since the last event. Update the weight and write a decay-kind events row.decay weight threshold moves to decaying; it is signalled in the proposals channel to the gateway.decaying mnest below archive weight with ts_last > 90 days enters the list of archival proposals shown to Roberto.min proto weight is deleted (anti-noise).uses >= SYNTH_TRIGGER_USES and weight >= SYNTH_TRIGGER_WEIGHT; signal them to the synt as candidates for synthesis.workspace/.mnestome/snapshots/YYYY-MM.sqlite.The ager is a pure example of a component that only does maintenance: it does not modify the structure of mnests, does not create executors, does not speak to the user. It proposes; the deciders are synt + Roberto, or the archival policy that the gateway applies in the next turn.
On the first of the month (UTC), the ager produces a snapshot of the live file:
workspace/.mnestome/snapshots/2026-04.sqlite # current month
workspace/.mnestome/snapshots/2026-03.sqlite.zst # older, compressed
workspace/.mnestome/snapshots/2026-02.sqlite.zst
...
The snapshot serves three purposes: rollback in case of corruption of
the live file, historical analysis of the graph, trace for whoever
wants to understand how Metnos «formed» over time.
Snapshots older than 12 months are .zst-compressed but
never deleted: history is a first-rate datum.
The live file would stay up even when full, but for performance and cleanliness a periodic pruning helps:
superseded and archived mnests are moved to a mnests_archive table after 90 days (still in the same SQLite file);events table is partitioned by year (tables events_2026, events_2027, ...). Only the current year is in the live schema; previous years move to a second SQLite file events_history.sqlite;VACUUM runs monthly right after the snapshot.
When an executor moves to archived, its mnests move to
superseded with reason = 'executor archived';
they remain readable, are excluded from the v_mnestome
view, and after 90 days move to the archive table.
The term has two normative forms:
The double form is intentional and to be preserved. Translating mnestoma into mnestome in English gives the English reader the right reflex (the biological suffix evokes an emergent graph, like the microbiome). Translating mnestome into mnestoma in Italian follows the phonetic rule that avoids suffixes felt as incongruous (mnestome in Italian would sound like a verbal imperative, «you, memorise!»).
At first boot, the mnestome is empty. The question «then where do we start?» has three concrete answers:
state = 'seed' to distinguish them and weight BOOTSTRAP_WEIGHT (see mnest.html ch. 6).
The user can inspect the mnestome from the CLI (via the
Metnos mnestome command):
Metnos mnestome list # all active mnests
Metnos mnestome list --tag invoice # filtered by tag
Metnos mnestome top 20 # the 20 heaviest
Metnos mnestome graph executor fs_read # neighbourhood of an executor
Metnos mnestome proto # current proto-mnests
Metnos mnestome history mnest_01HW... # event history of a mnest
Metnos mnestome snapshot --month 2026-03 # opens the monthly snapshot
The web dashboard (see observability.html, in Italian and pending rewrite) has a graphical view of the same content, with filters and drill-down. The transparency rule: the user can always know what Metnos thinks it knows.
Metnos — mnestome microdesign v1.1 — 2026-04-24
New canonical doc (concept introduced by v1.1).