- holo-metacognitive
- What it does
- Why self-reference
- Installation
- Usage
- Results
- Self-test
- Demo 1 β Basic storage with provenance
- Demo 2 β Query log and trajectory
- Demo 3 β Introspection
- Demo 4 β Self-query through
ask() - Demo 5 β Consensus across sources
- Demo 6 β Meta-facts grow with the store
- Demo 7 β Forgetting updates all layers
- Demo 8 β Self-verification
- Demo 9 β Anomaly detection
- Demo 10 β Full health snapshot
- JSON export
- API reference
- Design notes
- Limitations
- Citation
- References
- License
- What it does
holo-metacognitive
A memory that holds facts about itself, verifies them, and reports its own trajectory.
Standard memory tools report their state through a side channel β a
stats() method, a log file, a dashboard. The state exists but is not
addressable through the same interface as the content.
This substrate closes that gap. Three kinds of facts are stored and queried the same way:
- Content β labels and weights for external items
- Provenance β which source contributed which weight
- Self-facts β counts, magnitudes, trends, self-verification
Every one of the three is retrievable through the same ask()
primitive. The caller does not specify which kind they are asking for.
The substrate reports what it has.
What it does
from holo_metacognitive import MetaMemory
mem = MetaMemory(d=2048)
mem.store("apple", weight=1.0, source="book")
mem.store("apple", weight=0.5, source="witness")
mem.query("apple")
# Same interface, three layers
mem.ask("apple") # [item] apple: verdict=YES, conf=+0.988
mem.ask("n_items") # [meta] n_items = 1.0
mem.ask("book") # [source] book: total_weight=1.0
# Provenance
mem.sources_of("apple") # {"book": 1.0, "witness": 0.5}
mem.consensus("apple") # {"consensus": 0.92, "shares": {...}}
# Trajectory
mem.trajectory("apple") # [{"tick": 1, "verdict": "YES", ...}]
mem.confidence_trend() # slope of recent query confidence
# Self-verification
mem.verify_meta() # 5/5 checks passed
# Anomalies
mem.anomalies() # unusual items
# Full report
mem.health() # stats + meta + verification + anomalies
Why self-reference
Standard memory tools are flat. A vector database accepts an embedding and returns neighbors. A KV cache accepts a key and returns a value. A dashboard shows the state but does not let the user query it.
The metacognitive layer makes the substrate's own state addressable
through the same primitive as its content. A query for "n_items"
returns the item count; a query for "apple" returns the item.
There is no separate reporting interface for the two.
The self-verification layer goes one step further: the substrate can be asked whether it trusts its own facts, and the answer comes from the same substrate that holds those facts. The anomalies layer does the same for individual items.
Installation
pip install numpy
No other dependencies. Single file, approximately 700 lines.
Usage
CLI
python holo_metacognitive.py
python holo_metacognitive.py --output results/
Runs ten demonstrations and writes a JSON state file.
Python
from holo_metacognitive import MetaMemory
mem = MetaMemory(d=2048, threshold=0.05)
# Storage with provenance
mem.store("earth_round", weight=1.0, source="textbook")
mem.store("moon_cheese", weight=0.4, source="folklore")
# Queries log themselves
mem.query("earth_round")
mem.query("moon_cheese")
mem.query("jupiter_capital") # UNKNOWN, logged as doubt
# The three layers under one interface
hits = mem.ask("earth_round") # item
hits = mem.ask("n_items") # meta
hits = mem.ask("textbook") # source
# Provenance analysis
mem.sources_of("earth_round") # {"textbook": 1.0}
mem.consensus("earth_round") # consensus score
# Trajectory
mem.trajectory("earth_round") # list of query records
mem.confidence_trend(window=10) # slope of recent confidence
# Self-verification
report = mem.verify_meta()
print(report["n_ok"], "/", report["n_checks"], "checks passed")
# Anomaly detection
for a in mem.anomalies():
print(a["kind"], a["label"])
# Full state
health = mem.health()
mem.save_json("state.json")
Results
All results at D=2048, threshold=0.05.
Self-test
Four checks before any demonstration:
| Check | Result |
|---|---|
| bind/unbind identity | PASS |
| raw projection | PASS |
| meta-fact round-trip (n_items = 7) | PASS |
| forget decrements count (n_items = 5) | PASS |
Demo 1 β Basic storage with provenance
Two items stored with two sources each.
| Label | Weight | Sources |
|---|---|---|
| apple | 1.50 | book=1.0, witness=0.5 |
| orange | 1.00 | book=1.0 |
Source totals: book: 2.00, witness: 0.50.
Demo 2 β Query log and trajectory
Query sequence: apple, pear, apple, pear, orange. Trajectory for
apple shows two queries at ticks 1 and 3, both with confidence
+1.496. Trajectory for pear shows ticks 2 and 4 at +0.279.
Query summary:
n_queries: 5
by_verdict: {'YES': 4, 'UNKNOWN': 1}
mean_confidence: 0.710
n_doubt: 1
confidence_trend: -0.299
The trend is negative because the sequence ends with an UNKNOWN verdict (orange is not stored), pulling the slope down.
Demo 3 β Introspection
The introspect() method returns the full meta snapshot as a dict:
| Key | Value |
|---|---|
| confidence_trend | 0.0 |
| dimension | 2048.0 |
| magnitude | 2.22 |
| mean_confidence | 1.48 |
| n_doubt | 0.0 |
| n_items | 2.0 |
| n_queries | 2.0 |
| n_sources | 2.0 |
| source_book_weight | 2.0 |
| source_witness_weight | 1.0 |
| threshold | 0.05 |
Dimension is stored exactly (2048.0). Magnitude is quantized to two decimal places. Counts are exact.
Demo 4 β Self-query through ask()
Seven example queries, each returning heterogeneous hits.
| Query | Result |
|---|---|
| apple | [item] verdict=YES, conf=+0.988 |
| n_items | [meta] n_items = 2.0 |
| book | [source] total_weight=1.00 |
| n_queries | [meta] n_queries = 1.0 |
| source_book_weight | [meta] = 1.0 |
| dimension | [meta] = 2048.0 |
| unknown_label | (no hits) |
The same primitive answered "what is apple?" and "how many items do I have?" and "what is my dimension?"
Demo 5 β Consensus across sources
Three items with different source distributions.
| Label | Sources | Consensus | Shares |
|---|---|---|---|
| well_attested | 2 | 0.561 | book=0.91, forum=0.09 |
| disputed | 2 | 0.000 | book=0.50, forum=0.50 |
| controversial | 3 | 0.000 | book=0.33, forum=0.33, witness=0.33 |
Consensus is 1 - H/log(N). A dominant source gives 0.561. Balanced
sources give 0.000.
Demo 6 β Meta-facts grow with the store
Six steps, five items added per step.
| Step | n_items | n_sources | n_queries | magnitude | trend |
|---|---|---|---|---|---|
| 0 | 5 | 3 | 1 | 2.170 | n/a |
| 1 | 10 | 3 | 2 | 3.160 | 1.090 |
| 2 | 15 | 3 | 3 | 3.890 | 1.040 |
| 3 | 20 | 3 | 4 | 4.480 | 1.030 |
| 4 | 25 | 3 | 5 | 4.990 | 1.000 |
| 5 | 30 | 3 | 6 | 5.530 | 1.020 |
Magnitude grows sublinearly (βN). Trend stabilizes near 1.0 as the sequence progresses.
Demo 7 β Forgetting updates all layers
Store 10 items, then forget two.
| After store | After forget | |
|---|---|---|
| n_items | 10 | 8 |
| magnitude | 3.190 | 2.840 |
| source_book_weight | 10.000 | 8.000 |
The count, magnitude, and source total all update. This is the
fix from the previous version, where n_items was wrong after
forgetting.
Demo 8 β Self-verification
Five meta-checks against source-of-truth state.
| Key | Expected | Stored | Tolerance | Diff | ok |
|---|---|---|---|---|---|
| n_items | 2.000 | 2.0000 | 1.0000 | 0.0000 | Y |
| n_sources | 2.000 | 2.0000 | 1.0000 | 0.0000 | Y |
| n_queries | 3.000 | 3.0000 | 1.0000 | 0.0000 | Y |
| magnitude | 1.403 | 1.4000 | 0.0100 | 0.0032 | Y |
| dimension | 2048.000 | 2048.0000 | 4.0000 | 0.0000 | Y |
All 5 checks pass. The magnitude check has a diff of 0.0032, within
the 0.01 tolerance set by the quantization scale (100 buckets per unit).
Demo 9 β Anomaly detection
Two anomalies detected in a hand-crafted store:
| Kind | Label | Details |
|---|---|---|
| high_doubt | never_stored | unknown_count=5 |
| split_sources | split | consensus=2.9e-12, n_sources=2 |
The high_doubt anomaly fires because a query was issued 5 times for
a label that was never stored. The split_sources anomaly fires
because two sources contributed equal weight (consensus β 0).
Demo 10 β Full health snapshot
The health() method combines everything:
- stats (counts, magnitudes)
- verification (5/5 checks passed)
- anomalies (empty in this run)
- query summary (mean confidence, trend, doubt count)
The output is the substrate's full self-report.
JSON export
save_json writes a complete state file including:
{
"d": 2048,
"n_items": 3,
"n_queries": 2,
"trace_magnitude": 1.7427,
"meta_magnitude": 3.3444,
"items": { ... },
"meta_snapshot": {
"confidence_trend": 0.99,
"dimension": 2048.0,
"magnitude": 1.74,
"n_doubt": 0.0,
"n_items": 3.0,
"n_queries": 2.0,
"n_sources": 2.0,
"threshold": 0.05
},
"query_log": [ ... ],
"anomalies": [],
"verification": {
"n_checks": 5,
"n_ok": 5,
"all_ok": true,
"checks": [ ... ]
}
}
The meta_magnitude is non-zero in the saved file (fix from the
previous version, where save_json did not refresh the meta-trace).
API reference
MetaMemory
MetaMemory(d=2048, threshold=0.05, key=None, meta_buckets=4096)
Storage
store(label, weight=1.0, source="user")β add weight for label.forget(label)β remove all trace of label.
Query
query(label, log=True) -> dictβ verdict, confidence, raw, weight.
Provenance
sources_of(label) -> dictβ per-source weights for label.consensus(label) -> dictβ n_sources, consensus score, shares.
Trajectory
trajectory(label, limit=None) -> listβ query records for label.confidence_trend(window=20) -> float | Noneβ slope of recent queries.query_summary() -> dictβ aggregated query statistics.
Meta
refresh_meta()β rebuild the meta-trace from current state.query_meta(key) -> float | Noneβ retrieve a meta-fact by key.meta_keys() -> listβ all available meta keys.introspect() -> dictβ full meta snapshot as a dict.
Self-verification
verify_meta() -> dictβ re-derive meta-facts and compare.
Anomalies
anomalies() -> listβ unusual items with kind and details.
Unified interface
ask(query) -> dictβ heterogeneous search across all layers.health() -> dictβ full snapshot (stats + meta + verification + anomalies).
Diagnostics
stats() -> dictβ counts and magnitudes.save_json(path)β full state with meta snapshot, query log, anomalies, and verification report.
Query result
{
"label": str,
"verdict": "YES" | "UNKNOWN",
"confidence": float,
"raw": float,
"weight": float,
}
ask() result
{
"query": str,
"hits": [
{"type": "item", "label": str, "verdict": str,
"confidence": float, "weight": float},
{"type": "meta", "key": str, "value": float},
{"type": "source", "name": str, "total_weight": float},
]
}
Design notes
Meta-facts are quantized
Meta-values are stored as bucket indices in a codebook of 4096
vectors. The value n_items = 7 is stored as
bind(meta_key_vector("n_items"), meta_value_vector(7)). Retrieval
unbinds the key and classifies the result against the bucket
codebook. The bucket index divided by the scale gives the value.
This means meta-facts are approximate to one bucket. The tolerance
for each key is 1/scale, set at refresh time. Counts have scale 1.0
(tolerance 1). Magnitude has scale 100.0 (tolerance 0.01). Dimension
has scale 0.25 (tolerance 4, exact for D=2048).
Why ticks, not wall-clock
Query timestamps use a monotonic counter instead of time.time().
Wall-clock timestamps in a fast loop are indistinguishable; the
previous version logged five queries with t=1791494125.885 and
t=1791494125.886. Ticks distinguish them cleanly.
Self-verification
verify_meta() re-derives a set of meta-facts from the store's
actual state and compares against the stored values. The check
uses the per-key tolerance from the meta storage. A mismatch means
the meta-trace and the state have diverged β a signal that the
substrate has become inconsistent with itself.
Anomalies
Three anomaly types:
- low_confidence: verdict YES but confidence below twice the threshold.
- high_doubt: label queried 3+ times, always UNKNOWN.
- split_sources: item with 2+ sources, consensus below 0.5.
Each is a heuristic. The substrate reports what it finds; the user decides whether the anomaly matters.
Limitations
Meta-facts are approximate. Quantization to 4096 buckets limits resolution. Counts are exact up to ~4000. Magnitudes are exact to 0.01. Values beyond the bucket range are clamped.
No meta-of-meta. Facts about the meta-trace itself (its magnitude, its bucket usage) are not stored as meta-facts. Adding them is straightforward but not implemented.
Anomaly thresholds are fixed. The heuristic thresholds
(confidence < 2 * threshold, unknown_count >= 3, consensus < 0.5)
are not learned from the store's history. A user who wants different
sensitivity changes the constants.
No cross-meta inference. The substrate cannot answer "which source contributes most to my confidence?" because confidence is a scalar per query and sources are per item. Extending the meta layer to infer attribution across items is a separate project.
Keys are still per-store. The keyed codebook layer from
holo-program is available but the metacognitive layer does not use
it. A keyed store would need to re-derive meta-vectors under the same
key.
No consolidation integration. The four-axis consolidation layer
would decay items over time. Here, forget() is explicit. A combined
store would need to decide whether consolidation updates the meta-facts
of its own accord.
Citation
@misc{holo-metacognitive2026,
title = {holo-metacognitive: A memory that holds facts about itself},
author = {zeechimp},
year = {2026},
note = {Three-layer memory with content, provenance, and
self-facts under one interface.}
}
References
- Plate, T. A. "Holographic Reduced Representations." IEEE Transactions on Neural Networks 6:3 (1995), 623β641.
- Kanerva, P. "Hyperdimensional Computing." Cognitive Computation 1:2 (2009), 139β159.
- Gayler, R. W. "Vector Symbolic Architectures Answer Jackendoff's Challenges." ICCS/ASCS (2003).
License
Apache 2.0