tastebud-memory
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 8 GitHub stars
Code Fail
- spawnSync — Synchronous process spawning in mcp-server/server.mjs
- spawnSync — Synchronous process spawning in tagger.mjs
- process.env — Environment variable access in tagger.mjs
- network request — Outbound network request in tagger.mjs
- process.env — Environment variable access in tastebud.mjs
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
A chef's palate for AI agent memory; Un-mix any day's work into its exact projects, and detect workstreams nobody has named yet. Hyperdimensional fingerprints, zero dependencies.
👅 tastebud-memory
Compositional project fingerprints for AI agent memory. Give every project a deterministic
high-dimensional identity vector. Every day's work becomes a weighted blend of those vectors.
One "taste" (a dot product) decomposes any day back into its exact ingredients, enumerates
every day a project ever touched, and detects ingredients nobody has named yet.
Zero dependencies. Two JSON files. ~600 lines of Node.
What it looks like
$ node tastebud.mjs decode 2026-01-12 # un-mix one day from its 4096-dim vector alone
2026-01-12 - Dosing pump driver; recipe-site deploy; soil sensors moved to bed 2
recovered from vector alone (vs actual):
aquarium-controller est=0.502 actual=0.500
recipe-site est=0.296 actual=0.300
garden-sensors est=0.191 actual=0.200
$ node tastebud.mjs gaps # what's been worked on but never documented?
workstreams in logs with NO project file:
aquarium-controller 4 day(s) mass=2.150 first=2026-01-10
home-lab 3 day(s) mass=1.550 first=2026-01-05
sourdough-lab 2 day(s) mass=0.900 first=2026-01-15 [NOT EVEN IN CODEBOOK]
$ node tastebud.mjs tasteslike sourdough-lab # the unknown ingredient: what is it close to?
sourdough-lab [UNKNOWN INGREDIENT - not in codebook]
keeps company with (rarity-weighted co-occurrence):
recipe-site 0.463
aquarium-controller 0.201
$ node tastebud.mjs unknowns # triage: which unknowns are RIPE to decide on?
unknowns: 1 total (decide 1, maturing 0)
sourdough-lab open 155d 2 day(s) mass=0.900 [OVERDUE ] -> alias->recipe-site
Those last two are the headline feature. sourdough-lab doesn't exist anywhere as a project:
the nightly tagger invented the slug because nothing in the codebook fit, and the system
flagged it and placed it next to its nearest relative. Your agent notices new workstreams
forming before you've named them and then helps you decide what to do about each one. The-> alias->recipe-site is a recommendation, not a decision: sourdough-lab keeps company
almost entirely with recipe-site, so the system reads it as the same work and suggests folding
it in. You stay in charge: you could mint it as its own project instead, dismiss it, or wait.
The pipeline
daily log (markdown)
│ nightly LLM tagger (rules + your codebook; invents slugs when nothing fits)
▼
composition row {"date":"2026-01-12","major":[{"slug":"aquarium-controller","w":0.5},...]}
│ deterministic: slug string → seeded ±1 hypervector, day = weighted sum
▼
fingerprint (4096-dim)
│
├─ decode / where / first / cooccur / window / diff / gaps (exact membership queries)
├─ similar / drift / tasteslike / backtest (vector-layer extras)
├─ unknowns / mint / alias / dismiss / watch / autofile (ripen-then-decide triage loop)
└─ MCP server → your agent tastes before it reads
The idea (and where it came from)
This started as a question about hexadecimal colors: what if every project had a unique color,
and a day's work blended them into a new color you could un-mix? The problem is that color
can't do that. Three channels can't carry the membership of 50 projects, which is why mixed
paint can't be un-mixed.
The metaphor that actually works is a chef's palate. A trained chef tastes an unfamiliar
dish and names every ingredient in it, estimates the proportions, and (the key move) notices
when there's something in the dish he doesn't recognize. That's what this does, with
~30-year-old math: hyperdimensional computing
(Kanerva) / vector symbolic architectures.
- Each project slug deterministically seeds a 4,096-dimension ±1 vector. Random
high-dimensional vectors are nearly orthogonal, so they don't interfere. - A day's fingerprint is the weighted sum of its projects' vectors.
- Decoding is a dot product against the codebook: projects in the blend score close to
their weight, and absent projects score close to zero. Mixing is reversible, the thing color
couldn't do. - The residual, the mass the codebook can't explain, is the unknown ingredient detector.
When your agent starts working on something that has no name yet, this notices before you do.
Why bother? (what semantic search can't do)
We baselined an agent's real memory (92 days, ~400 files) with embedding search before building
this. Semantic search was good at date lookups and well-named topics, and structurally
incapable of:
- Enumeration: "list ALL days that touched project X" (search returns representatives, never
the complete set) - Origin under aliasing: "when did X start, including under its old name?" (recency and
volume bury the origin; this was a total miss in our baseline) - Temporal set-difference: "active in March, dead by June"
- Absence: "which workstreams never got documentation?" (you can't embed a negation)
One concrete failure from that baseline, because it's instructive. A business project had been
renamed early in its life, and we asked search "when did this start, including under its
earlier name?" with three increasingly charitable query phrasings. Every one returned the
later, high-volume era of the project; the actual origin date and rename event never surfaced,
because similarity ranking structurally favors where the bulk of the writing is, and origins
are by definition thin. tastebud.mjs first <slug> answers it exactly, because the codebook
records the alias and the composition table records the date. Absence queries fail even worse:
asked "which workstreams never got a project file," embedding search matched the literal phrase
"project file" to documentation about the memory system itself. It cannot reason about what
isn't there.
Fingerprints answer all four exactly, in milliseconds, because composition is recorded, not
inferred. Tastebud complements semantic search (meaning); it doesn't replace it (membership).
The unknown-ingredient loop (detect, ripen, decide, reverse)
Detecting an unnamed workstream is only half the job. The other half is deciding what it is,
without being nagged about every fleeting one-off and without making a single irreversible
mistake. Tastebud closes that loop with a full triage + reversible-decision system. The chef
keeps tasting; you only get asked once a dish is worth a verdict.
Detection is continuous but silent. Every night the sweeper notices new unknown slugs and
logs them. No pings. A brand-new slug seen once is not a reason to interrupt you.
Mature before asking. An unknown is not surfaced for a decision until it ripens: it has to
recur across days, accumulate real major weight, or age past about a week. Thin one-offs sit
quietly in a Maturing bucket and never nag. A workstream that shows up for one afternoon and
vanishes was noise; a workstream that keeps coming back has earned a question. All the thresholds
are env-tunable (TASTEBUD_RIPE_DAYS, TASTEBUD_RIPE_MASS, TASTEBUD_RIPE_AGE_DAYS, and more).
Auto-file the obvious. If an unknown already has a project file on disk (config projectsDir),
the nightly sweeper files it into the codebook automatically. A file means a human already judged
it a real project, so there is nothing to ask. Logged, not pinged.
Weekly digest decides only ripe items. Once a week a review surfaces only the ripe unknowns,
each with a recommendation (mint / alias / dismiss / watch) plus the context behind
it, pushed through the config notifyCommand. Everything still maturing stays out of your way.
Every decision is reversible. Triage state lives in a persistent ledger
(<dataDir>/unknowns-ledger.json). Nothing you decide is permanent:
- dismiss means "not now," not "never." A dismissed one-off revives if it starts growing
again, and comes back recommended as something to watch. - mint writes the slug into the codebook, and is fully undoable with
mint --undo. - watch parks it on a watchlist: out of the decide queue, still in view.
- alias folds a name into an existing project and resolves it. The engine treats codebook
aliases as known, so the unknown leaves the list for good (until you remove the alias).
$ node tastebud.mjs unknowns # what is ripe to decide on right now?
unknowns: 1 total (decide 1, maturing 0)
sourdough-lab open 155d 2 day(s) mass=0.900 [OVERDUE ] -> alias->recipe-site
$ node tastebud.mjs alias sourdough-lab recipe-site # fold it in; it now resolves
$ node tastebud.mjs watch sourdough-lab "keep an eye on it" # or defer the call
$ node tastebud.mjs mint sourdough-lab --class product # or make it its own project
$ node tastebud.mjs mint sourdough-lab --undo # changed your mind: undo it
The recommendation is a hint, never a decision. Here sourdough-lab co-occurs almost entirely
with recipe-site, so the system suggests aliasing it; a human who knows it is a distinct effort
can mint it instead. The point of the loop is that you make the call, late enough to be sure, and
can always take it back.
Quickstart (60 seconds)
git clone https://github.com/Mikhail-Za/tastebud-memory && cd tastebud-memory
node tastebud.mjs check # validate the sample data
node tastebud.mjs decode 2026-01-12 # un-mix one day from its vector alone
node tastebud.mjs where aquarium-controller # every day that project ever touched
node tastebud.mjs gaps # workstreams with no documentation
node tastebud.mjs tasteslike sourdough-lab # an UNKNOWN ingredient: what is it close to?
node tastebud.mjs backtest aquarium-controller # would the detector have caught this project emerging?
node tastebud.mjs unknowns # the triage queue: which unknowns are ripe to decide?
node tastebud.mjs color 2026-01-12 # the original metaphor, as garnish
The unknown-ingredient loop adds its own small command set (all reversible, all snapshot before
they write):
node tastebud.mjs unknowns --write # write unknowns-report.md (Decide / Watching / Maturing)
node tastebud.mjs alias sourdough-lab recipe-site # fold a name into a project; it now resolves
node tastebud.mjs mint sourdough-lab --class product # promote an unknown to its own codebook slug
node tastebud.mjs mint sourdough-lab --undo # reverse a mint
node tastebud.mjs dismiss sourdough-lab "one-off" # "not now"; revives if it grows again
node tastebud.mjs watch sourdough-lab # park on the watchlist, out of the decide queue
node tastebud.mjs decisions # the persistent decision ledger, grouped by status
node tastebud.mjs autofile # dry-run filing unknowns that already have a project file
The sample data is a fictional fortnight that includes an emerging project and an unknown
ingredient, so every command above demonstrates something real.
Using it on your own memory
- Codebook: list your projects in
codebook.json(slug + aliases +has_file). Slugs are
permanent (they seed the vectors); add aliases instead of renaming. - Backfill: have a strong LLM read each daily log and emit
{major:[{slug,w}], minor:[], new:[]}
per day (rules inexamples/nightly-prompt.md). Verify a sample before trusting it. Seedocs/methodology.mdfor the gate/backtest protocol we used. - Nightly: schedule your platform's LLM to tag yesterday into
inbox/<date>.json
(prompt template provided), and runnode tagger.mjs nightly --writean hour later as the
deterministic sweeper. If the primary fails, a local model takes over and you get an alert
with the reason (notifyCommandin config can point at Slack, ntfy, a webhook, anything).
The same nightly pass logs new unknown slugs silently and auto-files any that already have a
project file (configprojectsDir); it does not interrupt you for either. - Weekly decision loop: once a week run
node tastebud.mjs unknowns --writeand review only
the ripe unknowns, each with a recommendation. Decide withmint/alias/dismiss/watch; every call is reversible and snapshots before it writes. Seedocs/production-pattern.mdfor the wiring. - Agent integration: register
mcp-server/server.mjs(standard MCP, stdio) so your agent
can taste before reading: decode a day in milliseconds, then fetch only the logs that matter.
What this is not
- Not a summarizer. A fingerprint is an index, not the content. The chef recovers the
ingredient list, not the recipe steps. Taste, identify, then fetch. - Not magic capacity. A bundle reliably holds a few dozen constituents at D=4096. Plenty
for a day, wrong for a year; aggregate windows instead. - Not a replacement for the codebook. Decoding requires reference vectors, like a palate
requires training. Unknown ingredients are detected as unexplained mass, then triaged.
Honest engineering notes
The full methodology, including the kill-gates this project had to pass before going live,
is in docs/methodology.md. Highlights: an adversarial verification pass
re-derived 31 of 92 days blind and found 2 real tagging errors (93.5% faithful); backtests
flagged emerging projects within 0-2 days; and our honest finding that the composition table
does most of the query work. The vector layer earns its keep on decode, drift, similarity, and
fixed-size encoding, not on basic lookups. Production wiring (primary LLM cron + deterministic
sweeper + alerted local fallback) is in docs/production-pattern.md.
License
MIT. Built by Mikhail Zaidi with Claude (Anthropic), June 2026.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found