twin memory

Versions & edits

Sending an item again with the same id edits it, and every version memory took is kept for your backend until the item goes.

There is no separate update call. To edit an item, add it again with the same id and the new content. Memory replaces what it holds and keeps the earlier copy as a version.

An edit is for fixing the same statement, such as a typo or a mistake. When something changes, such as a new address or a new plan, add a new item with a new id instead: memory keeps both, each with the day it was said, and shows them newest first. An edit keeps the item's first date, so an edit used for a change loses the earlier value and dates the new one too early.

Sending an id again replaces its text. Its about, metadata, expires and author stay as they were unless the request sends them; send null to clear one.

What makes a version

A new version is taken whenever what lands differs from what memory holds for that id:

  • new text
  • a new title or author
  • other about tags or metadata
  • a new expires, or null where there was one

The item's time does not change on an edit: once memory holds an item, its at is fixed. To move it in time, forget it and add it again.

Sending exactly the same item again, such as a retry, makes no version.

What an edit does

  • The stored copy is replaced, and the conversation it belongs to is filed again, so search finds the new words and no longer finds the old ones.
  • Records read from the old words are read again from the new ones when the conversation is next read.
  • Models never see earlier versions. read, ls and every search show only what the item says now.

Read an item's versions

/v1/memory/versions returns every version of one item, oldest first, and its state now. It takes a read and write key, because it returns text that was edited away. Do not give that key to a model.

curl https://api.twinmemory.dev/v1/memory/versions \
  -H "Authorization: Bearer $TWIN_MEMORY_API_KEY" \
  -H "X-Twin-Account: user_42" \
  -H "Content-Type: application/json" \
  -d '{ "id": "pref-diet" }'

After the note pref-diet was added, then sent again with new text:

{
  "id": "pref-diet",
  "state": "live",
  "history": [
    {
      "event": "version",
      "at": "2026-10-21T10:23:40.598077+00:00",
      "version": 1,
      "item": {
        "id": "pref-diet",
        "kind": "note",
        "text": "Alice is vegetarian and allergic to peanuts.",
        "at": "2026-10-02T12:00:00+00:00",
        "metadata": { "source": "crm" }
      }
    },
    {
      "event": "version",
      "at": "2026-10-21T10:23:40.600223+00:00",
      "version": 2,
      "item": {
        "id": "pref-diet",
        "kind": "note",
        "text": "Alice is vegan and allergic to peanuts.",
        "at": "2026-10-02T12:00:00+00:00",
        "metadata": { "source": "crm" }
      }
    }
  ]
}
  • at on a version is when memory took it. item.at is the item's own time.
  • item shows what memory held, in the shape add takes. A role is kept only as the kind of author, so it may not appear as you sent it.

States

stateMeaning
liveThe item is held. The last version is what it says now.
expiredIts expires time has passed.
forgottenIt was erased by forget.
unknownMemory never took an item by this id. history is empty.

When the item goes

When an item is forgotten or expires, every version goes with it. One line stays, saying when it went and why, with nothing of what it said:

{
  "id": "pref-diet",
  "state": "forgotten",
  "history": [{ "event": "gone", "at": "2026-10-21T10:23:40.619860+00:00", "why": "forgotten" }]
}

If you add the same id again after that, its versions start again after that line.

Versions are kept only for items you add. They are not a backup: the forget receipt counts the versions it erased under versions.

On this page