greatmemory

Getting started

Ingest, use, and remove data

Public examples for adding text and files, using memory in prompts, and deleting imported data by id.

The full data loop is small: ingest text into a space, use it through recall or context blocks, and remove it by id when it should no longer be available.

Use a space for each project, tenant, user, or environment. That keeps imports isolated and makes cleanup predictable.

1. Ingest text

For one-off memories, the CLI is the shortest path:

gmem add "The staging database runs Postgres 17 with pgvector." --space demo

For apps, jobs, and imports, use the REST API and keep the returned id:

MEMORY_ID=$(
  curl -s http://127.0.0.1:7437/v1/memories \
    -H 'Content-Type: application/json' \
    -d '{"space":"demo","content":"The staging database runs Postgres 17 with pgvector."}' |
  jq -r '.id'
)

echo "$MEMORY_ID"

Adds return quickly (202 Accepted): greatmemory chunks and embeds in the background through a bounded queue, so imports can stream data without waiting for each embedding operation.

2. Ingest files

greatmemory stores text. For plain-text files, read the file and POST it. Prefix the source path into the memory body so later retrieval has provenance.

export GM_URL=http://127.0.0.1:7437
export SPACE=docs-demo

mkdir -p .greatmemory-import
: > .greatmemory-import/ids.txt

find ./docs -type f \( -name '*.md' -o -name '*.txt' -o -name '*.json' -o -name '*.csv' \) -print0 |
while IFS= read -r -d '' file; do
  id=$(
    jq -n --rawfile content "$file" \
      --arg space "$SPACE" \
      --arg source "$file" \
      '{space:$space, content:("SOURCE: " + $source + "\n\n" + $content)}' |
    curl -sS "$GM_URL/v1/memories" \
      -H 'Content-Type: application/json' \
      -d @- |
    jq -r '.id'
  )
  printf '%s\t%s\n' "$id" "$file" >> .greatmemory-import/ids.txt
done

For PDF, DOCX, HTML, or slide decks, run an extractor first and POST the extracted text. Keep the source URI in the content prefix:

pdftotext ./contracts/acme-master-services.pdf - |
jq -Rs --arg space contracts \
  '{space:$space, content:("SOURCE: ./contracts/acme-master-services.pdf\n\n" + .)}' |
curl -sS "$GM_URL/v1/memories" \
  -H 'Content-Type: application/json' \
  -d @-

Cloud examples are in the provider guides:

3. Use the data

Use recall when you want scored chunks and facts:

gmem search "what does staging run?" --space demo

Use mode: "context" when you want a block ready to inject into an LLM prompt:

curl -s http://127.0.0.1:7437/v1/search \
  -H 'Content-Type: application/json' \
  -d '{"space":"demo","query":"staging database setup","mode":"context","max_tokens":1000}'

For an agent loop, the rhythm is:

  1. POST /v1/search with mode: "context" before the model call.
  2. Put the returned context block into the system or developer prompt.
  3. POST /v1/memories after the turn for durable facts, decisions, and outcomes.

With MCP, the equivalent tools are get_context, recall, and remember.

4. Remove data

Delete a memory by id when it should no longer be retrieved:

curl -s -X DELETE "$GM_URL/v1/memories/$MEMORY_ID"

If you imported many files, delete from the import manifest:

cut -f1 .greatmemory-import/ids.txt |
while read -r id; do
  curl -s -X DELETE "$GM_URL/v1/memories/$id" >/dev/null
done

With MCP, call forget with the memory_id returned by remember.

Facts already extracted from a deleted memory may remain as audited graph history but lose their source link. If you need a clean-room test, use a dedicated space or data directory for the import run.

Minimal TypeScript loop

const GM = "http://127.0.0.1:7437";
const SPACE = "demo";

async function remember(content: string) {
  const res = await fetch(`${GM}/v1/memories`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ space: SPACE, content }),
  });
  if (!res.ok) throw new Error(`remember failed: ${res.status}`);
  return (await res.json()).id as string;
}

async function context(query: string) {
  const res = await fetch(`${GM}/v1/search`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ space: SPACE, query, mode: "context", max_tokens: 1000 }),
  });
  if (!res.ok) throw new Error(`search failed: ${res.status}`);
  return (await res.json()).context as string;
}

async function forget(memoryId: string) {
  const res = await fetch(`${GM}/v1/memories/${memoryId}`, { method: "DELETE" });
  if (!res.ok) throw new Error(`delete failed: ${res.status}`);
}