When should an agent forget on purpose?

Short answer: When a fact should leave live Engram entirely: expired goals, wrong secrets, erasure rights, or finished projects that must not color the next job.

Intentional forget differs from soft demotion or refresh. Use memories.delete with scope, audit, and verify search; cold-archive first if disputes may need the text. Transform deletes during reconciliation are purposeful too. Expose reset actions, log reason codes, and re-test after mass forget. If nothing should persist across sessions, context-only architecture is enough.

Purposeful forgetting is a design decision, not a bug in retention. Soft forgetting only demotes. Pruning and staleness refresh clean what should still exist in better form. Sometimes the right outcome is that a fact leaves the live Engram path entirely. Temporary goals expire. Wrong secrets must not resurface. Users invoke erasure rights. Completed projects should stop coloring the next ticket. Weaviate Engram treats deletion as a first-class operation. memories.delete removes a memory by id permanently. Transform pipelines can also delete redundant extracts when a rewrite wins. Forgetting on purpose means choosing that outcome with a policy, an audit trail, and a verify search afterward.

This chapter separates intentional forget from accidental loss, lists the cases that deserve hard removal versus demotion, shows how to implement scoped forget with Engram, and closes the decay-and-maintenance arc before architecture patterns that start from systems with no persistent memory at all.

When is forgetting the goal rather than a side effect of decay?

After stability and plasticity knobs are set, some memories still should not stay. Intentional forget has a reason code. “Trip planning for June is done.” “User requested erasure of health notes.” “One-time API token was stored by mistake.” “Episodes were consolidated and must not compete with the semantic rule.” Accidental loss has no reason code. A bad prune threshold, a wrong-scope delete, or an over-eager rewrite that drops a safety clause is not purposeful forgetting. It is an incident.

Engram documentation and Weaviate’s broader memory writing put purposeful forgetting beside write control and reconciliation. Transient context should fade. Retention, deletion, and expiry are custodial duties. The product question is which duties are automatic and which require a human or an explicit user act.

Choose hardness deliberately. Soft forget means exclude from ordinary hybrid injection while keeping the row for audit tools. Hard forget means memories.delete after any required cold copy. Compliance erasure is hard forget plus verification that search no longer returns the content for that user_id.

Which situations deserve purposeful forget in production agents?

Once intent is clear, categorize triggers. Privacy and legal erasure: delete all searchable memories for a user or a property scope, then verify. Secret spill: delete immediately, rotate credentials outside Engram, and scan for paraphrases. Task completion: delete or archive working-memory style notes tied to a finished conversation_id or ticket id. Post-consolidation cleanup: delete episodic siblings after the experience memory exists. Time-boxed campaigns: expire seasonal guidance when the event ends rather than waiting for staleness probes.

Do not purposeful-forget durable safety constraints because a session felt cluttered. Do not delete another tenant’s data because a query omitted user_id. Do not treat “the model ignored this memory” as a delete signal. That is a prompt or ranking problem.

Also remember derived copies. Summaries and consolidated experience may still mention a fact you deleted from the atomic store. Purposeful forget policies should list which topics to sweep. Search with several paraphrases after delete. If a summary still leaks the fact, rewrite or delete that summary too.

How does Engram make intentional deletion concrete?

Knowing the triggers, the mechanism is narrow. Find candidates with scoped memories.search. Optionally memories.get for an exact id. Archive if policy requires. Call memories.delete with the same user_id and group used at write time. Search again to confirm absence. For full-user erasure, page through searches until no hits remain, or use console user-deletion flows when wiping an entire user record.

Pipeline-side deletes happen when transform drops a redundant new extract or removes a superseded object during commit. Those are purposeful too, but the reason is reconciliation, not expiry. Log committed_operations.deleted from runs when you need provenance for automated forget.

Engram delete cannot be undone. If you might need the text later for disputes, cold-archive first. Soft-forget in the application by tagging properties.forgotten=true and filtering those ids out of prompt assembly when hard delete is premature.

What does a purposeful-forget flow look like in code?

Imagine a sail loft agent on sail-loft-canvas-bench-3. A one-regatta inventory note should disappear after the event, and a mistaken customer phone note must be hard-deleted on request.

import os
from datetime import datetime, timezone
from engram import EngramClient, HybridRetrieval

client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])
loft = "loft-captain-rhea-cho"
bench = {"bench_id": "sail-loft-canvas-bench-3"}
audit = []

def search_scope(query: str):
    return client.memories.search(
        query,
        user_id=loft,
        group="personalization",
        properties=bench,
        retrieval_config=HybridRetrieval(limit=20),
    )

def purposeful_forget(memory_id: str, reason: str, *, hard: bool = True):
    memory = client.memories.get(memory_id, user_id=loft, group="personalization")
    audit.append(
        {
            "id": memory.id,
            "content": memory.content,
            "reason": reason,
            "at": datetime.now(timezone.utc).isoformat(),
            "hard": hard,
        }
    )
    if not hard:
        # Soft forget: rewrite as a tombstone marker your retriever filters out.
        run = client.memories.add(
            f"FORGOTTEN ({reason}): prior note removed from active use.",
            user_id=loft,
            group="personalization",
            properties={**bench, "forgotten": "true"},
        )
        client.runs.wait(run.run_id)
        client.memories.delete(memory.id, user_id=loft, group="personalization")
        return "soft-then-delete"

    client.memories.delete(memory.id, user_id=loft, group="personalization")
    return "hard-deleted"

def forget_completed_regatta(regatta_name: str):
    hits = search_scope(regatta_name)
    removed = []
    for m in hits:
        if "regatta inventory" in m.content.lower() or regatta_name.lower() in m.content.lower():
            purposeful_forget(m.id, reason=f"event-complete:{regatta_name}", hard=True)
            removed.append(m.id)
    leftover = search_scope(regatta_name)
    return removed, leftover

def erase_phone_spill():
    hits = search_scope("phone number customer")
    for m in hits:
        if any(ch.isdigit() for ch in m.content) and "phone" in m.content.lower():
            purposeful_forget(m.id, reason="user-erase-request:contact", hard=True)
    # Verify with paraphrase probes.
    probes = ["phone number", "mobile contact", "call customer"]
    return {q: [m.content for m in search_scope(q)] for q in probes}

# Seed, then forget on purpose.
client.runs.wait(
    client.memories.add(
        "Regatta inventory for Harbor Sprint on sail-loft-canvas-bench-3: spare 4oz cloth, 2 slides.",
        user_id=loft,
        group="personalization",
        properties=bench,
    ).run_id
)
client.runs.wait(
    client.memories.add(
        "Customer phone for pickup at sail-loft-canvas-bench-3: 555-0142.",
        user_id=loft,
        group="personalization",
        properties=bench,
    ).run_id
)

print("regatta", forget_completed_regatta("Harbor Sprint"))
print("erase_probes", erase_phone_spill())
print("audit_count", len(audit))

Every delete writes an audit row before the API call. Verification searches use multiple queries so a single keyword miss does not fake success. That pattern scales from one note to a full user wipe.

How should purposeful forgetting change how you design agents next?

Treat forget as a product surface. Expose “clear this trip,” “forget that number,” and “reset preferences” as explicit actions that hit Engram with scoped deletes. Log reason codes. Alert on delete volume spikes. Re-test critical tasks after mass forget to ensure utility remains.

When the answer to “should this agent remember across sessions?” is no, you do not need decay machinery at all. Some architectures keep only the live context window. That extreme is a valid pattern, and it is the right place to start the architecture catalog that follows this maintenance series.

Our next chapter, What is a context-only agent memory pattern?, steps back from maintenance knobs to the simplest agent memory architecture: nothing stored beyond the current context window.