Inspiration

A Twilio-style widget on a real shop site — Wink grooming already has a clerk in the corner. The clerk should remember the place, not the prompt. Same JavaScript on a clinic, a village line, a building-supply counter, or a compost stall. Only the room address changes.

This is a product page, not a contest entry.

What it does

@nature-labs/living-memory-js is the door. You do not pick Room vs World. You do not speak MCP.

import { enterSpace } from "@nature-labs/living-memory-js"

const room = await enterSpace(process.env.LIVING_MEMORY_URL)
await room.remember("The blue door on the left opens onto the rooftop.")
const found = await room.search("how do I get to the rooftop")

A Strands agent on top of that door can ask the same question. A local 4B model (Ollama qwen3.5:4b-mlx) called search, got the rooftop fact back from the hosted room, and answered: go through the blue door on the left. The model did not invent the path. The place remembered it.

How I built it

Three layers, kept apart:

  • Door — @nature-labs/living-memory-js on npm. enterSpace / remember / search. Zero runtime dependencies. Failures are SpaceError with four codes: ENTER_FAILED, MEMORY_TOO_LARGE, ROOM_FULL, REQUEST_FAILED. Raw MCP stays on error.cause.
  • Mind / mouth (pre-existing) — @nature-labs/living-memory-engine and @nature-labs/lme-mcp. Hosted rooms at lme.viibe.to. Disclosed as infrastructure, not as this week's invention.
  • Skin — createAgent({ model, space }) then agent.ask(...). Strands tools wrap the door. AWS / Bedrock was not used; the account was suspended, so the proof ran local.

The README is one path. A small model can follow three words without reading MCP docs.

Challenges I ran into

  • Guessing room.kind from tool names would have labeled a live free room as a world, because production rooms now list world_list and handoff. v1 leaves kind null rather than lie.
  • HTTP 429 is not ROOM_FULL. A full free room is a 16-item cap; reads still work. Mapping every 429 to “full” would teach the wrong failure.
  • Browser CORS on lme.viibe.to is an allowlist (living-memory.app, chat.viibe.to, localhost:5173), not a missing header. A widget on an arbitrary shop domain is a later origin add, not Access-Control-Allow-Origin: *.
  • A navy “LM” disc that says “cable not connected” is correct engineering and unsellable. The clerk people buy already exists on Wink. That design pass is next, not this writeup.

Accomplishments that I'm proud of

  • Published @nature-labs/living-memory-js@0.1.0.
  • Proved the chain on a real hosted room with a local 4B: search hit, natural answer, no Bedrock.
  • Kept the door package free of Strands, so a student can remember / search with no agent at all.

What I learned

Design the API until a small model can use it. If a 3B has to reason about JSON-RPC, the door leaked. Intelligence saved on plumbing is spent on the shop.

What's next

A landing on living-memory.app that looks like a tool, not a lab. One script tag, Wink-quality avatar, data-space as the only wire. Same JS, different room. No new repo. No Vercel (that origin is not on the CORS list).

Built With

Share this project:

Updates