Memory chip Make the write visible and the read too. A marker at the turn where something was stored, undo available in place, and a plain dated list where each item can be removed on its own. npx shadcn@latest add badge button npm i lucide-react Tokens this needs: --card, --card-foreground, --muted, --muted-foreground, --border, --status-warn, --chart-1 The status, chart, scale, state and direction names are an extension, not a rename. shadcn has --destructive and five --chart-* and nothing else in this territory. ──────────────────────────────────────────────────────────────────────── // MemoryChip.tsx ──────────────────────────────────────────────────────────────────────── import { X } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; /** * A stored item is text, a date and a scope. The date is what lets the viewer * judge it later; the scope is what stops a client's name from one project * turning up in a draft for another. */ export type Memory = { id: string; /** In the words it was stored in. "prefers metric units", not a key. */ text: string; savedAt: Date; /** Workspace or project the item belongs to. */ scope: string; }; const day = (d: Date) => d.toLocaleDateString("en-GB", { day: "numeric", month: "short", timeZone: "UTC" }); /** * The moment of writing. Sits on the turn that created the memory and names * what was stored. Undo is here rather than in a settings page because this * is the only moment the viewer has the context to judge it. */ export function SavedMarker({ memory, onUndo }: { memory: Memory; onUndo: (id: string) => void }) { return (
Saved: {memory.text}
); } /** * The moment of using. An answer that leaned on a stored fact says so, which * turns an unexplained assumption into an inference the viewer can check. */ export function UsedMarker({ memory, onShow }: { memory: Memory; onShow?: (id: string) => void }) { return ( ); } /** * The plain list. Every item, dated, removable on its own. An item from * another scope is labelled, because seeing it here is how a leak is caught. */ export function MemoryList({ memories, scope, onRemove }: { memories: Memory[]; /** The scope the viewer is in now. */ scope: string; onRemove: (id: string) => void; }) { return (

What it remembers

{memories.length === 0 ? (

Nothing yet.

) : ( )}
); } ──────────────────────────────────────────────────────────────────────── // demo.tsx ──────────────────────────────────────────────────────────────────────── import { useState } from "react"; import { MemoryList, SavedMarker, UsedMarker, type Memory } from "./MemoryChip"; /** * Two turns and the list beneath them. The first turn wrote a memory and * carries the marker with undo; the second read one and says so. The third * stored item came from a personal chat and is labelled as out of scope. */ const STORED: Memory[] = [ { id: "m1", text: "prefers metric units", savedAt: new Date("2026-03-04T12:00:00Z"), scope: "Rivera" }, { id: "m2", text: "works on the Rivera account", savedAt: new Date("2026-08-01T12:00:00Z"), scope: "Rivera" }, { id: "m3", text: "is a designer, not an engineer", savedAt: new Date("2026-08-19T12:00:00Z"), scope: "personal" }, ]; export default function Demo() { const [memories, setMemories] = useState(STORED); const forget = (id: string) => setMemories((ms) => ms.filter((m) => m.id !== id)); const saved = memories.find((m) => m.id === "m1"); const used = memories.find((m) => m.id === "m2"); return (

The unit is 3.2 m wide and 2.4 m deep, so it clears the doorway with 15 cm to spare. I'll keep to metric from here on.

{saved &&
}

The Rivera figures spreadsheet gives the floor area in square metres, so the totals below are in m² as well.

{used &&
}
); }