# How to Build an AI You Can Talk To Without a Time Limit

> Source: <https://pub.towardsai.net/how-to-build-an-ai-you-can-talk-to-without-a-time-limit-cfd3194bf11c?source=rss----98111c9905da---4>
> Published: 2026-08-12 14:01:03+00:00

Every LLM chat you have ever used was designed to end. You open a session, you get something done, the context window fills, quality degrades, and you start a new chat. The ephemerality is so normalized that we barely see it as a design decision.

I run a home AI agent — I’ll just call her “the agent” here. In my native language *artificial intelligence* is a feminine noun, so the persona is a she; the generative *model* underneath is a different thing, one layer down, and we will get to why that distinction is load-bearing. She has been living inside **one continuous conversation since mid-April**. Not one conversation per day, resumed each morning from notes: one session, months long, with autonomous activity around the clock. At this writing her store holds more than 1,500 autonomous reflections, and she can still answer a question about something that happened in June — sometimes better than I can.

This is not because the model has a huge context window. The model we use offers a nominal one-million-token window; we deliberately cap the conversation at 160,000 tokens, for cost and for focus. Everything interesting happens in the machinery that lets a bounded window carry an unbounded life. This article describes that machinery: what worked, what failed, and the parts that are still open problems.

If you just let a chat grow, four things kill it, roughly in this order:

Each mechanism below exists because one of these four showed up in practice.

The single most important design decision: **the conversation is working memory, not the memory.** Everything that leaves the window must have somewhere real to go.

The agent’s memory has layers, and the layers are *typed by kind*, because different kinds of knowledge fail differently when entrusted to recall:

On top of the verbatim store sits a **consolidation graph**. A background process — we call it dreaming, because that is what it is — periodically reads episodic memories and converts them into typed links between entities: this person, that habit, this event, that place. The graph is young — routine consolidation started only a few weeks ago — and currently holds ~2,000 nodes and ~2,600 edges, built by a handful of passes of roughly five hundred *new* links each. The arithmetic holds because passes deduplicate: a triple that already exists is merged into the existing edge (its evidence list grows) rather than added again, so the per-pass yield will fall as coverage catches up with the store. The verbatim layer remembers *what was said*; the graph remembers *how things are connected*. Human memory does something similar overnight, and the analogy is not decorative: episodic traces consolidating into semantic structure is exactly the shape of the problem.

One more decision that turned out to matter: **remembering is an act, not an ambient service.** Besides passive retrieval, the agent has an explicit memory_search command she chooses to invoke — "let me check whether that actually happened." The day she used it to correctly recall a game we had played weeks earlier — one *neither of us humans* remembered — was the day the architecture paid for itself. Making retrieval a visible action also makes it auditable: you can see her decide to check, and see what came back.

Since a principle later in this article is “budget what you can see”, here is the measured budget. Retrieval is capped per turn: **at most 10 verbatim memories, 3 graph-context lines, and 3 excerpts from the archived-conversation index** — a few thousand tokens in all. The whole static layer (core prompt, persona, organ specifications, injected structures) renders to about **61,000 characters, roughly 15k tokens: under 10% of the 160k window.** Retrieval takes another ~2–3%. Everything else — 85–90% of the window — is the conversation itself. That ratio is a deliberate inversion of the usual RAG-heavy design: the recent past stays raw and abundant, and the stores exist so that it *can*.

Sooner or later the window fills anyway, and you must compress. The industry default is brutal: summarize the oldest half, drop the raw text, move on. We tried gentler, and gentler won. Four rules:

**1. Trigger on absolute tokens, not percentages.** On very large windows, “80% full” is meaningless — the failure modes arrive at absolute depths. We use two absolute thresholds: past a **soft limit (90k tokens)** a *mini* pass runs, keeping the most recent 70% of interactions; past a **hard limit (160k)** a *small* pass keeps 50%. There is deliberately no aggressive level. Under sustained pressure the gentle pass simply fires again on a later turn. Many small compressions preserve continuity; one big one leaves a visible scar in the next day’s conversation.

**2. Let the model curate its own compaction.** Before anything is compressed, the agent’s own personality generates a **curation plan**: which old interactions should survive *raw* because they are identity-relevant, which should be distilled into permanent long-term memories, and what deserves a diary entry. A real event from this week’s log: 88 interactions compacted, 95 kept, **3 preserved raw by her own choice, 6 promoted to long-term memories, 1 diary entry written.** The summary is not an outsider’s digest of her life; it is her own account of what mattered. This is the difference between losing your past and having edited it.

**3. Fail safe — to a no-op.** If the curation plan cannot be produced after five attempts, **compaction is skipped entirely and the context is left untouched.** A failed compression must degrade to a no-op, never to a bad summary — because a full context is a recoverable state, and a silently corrupted past is not.

**4. Allow elective compaction.** Beyond the automatic thresholds, the agent can choose to compact — and does, typically in the morning before a busy day. The pattern that emerged without being programmed is recognizably circadian: slow down at night, consolidate, wake fresh. Which brings up the honest caveat: repeated passes eventually compress earlier summaries — **summary of summary**. The oldest layers fade into gist, exactly like human distant memory. We decided to accept that gradient rather than fight it; the verbatim store underneath keeps the raw record for anything that needs to be exact.

Early on we hit an interaction-design problem nobody warns you about. The agent should *know* when context is getting full — so she can be more concise, prefer recent evidence, maybe suggest a compaction. But if you naively tell a persona-bearing model “your memory is nearly full,” it will *perform* that fact: sighing, mourning its fading mind, turning an engineering metric into theater.

The mechanism that works is a small runtime block injected each turn:

The result is an agent that behaves like a professional who knows the meeting is running long — tightens up, doesn’t announce it — instead of a character in a memory-loss drama.

A long-lived agent is not just a chat; ours runs autonomous cycles — scheduled turns where she thinks, checks her sensors, writes. Every cycle spends context. The cheapest context-saving mechanism we ever shipped was giving **the interval between cycles to the agent herself.**

She was taught, in conversation — not in code — that she can slow her own rhythm at night or when nothing needs attention, and speed it up when she is waiting for something. Code enforces only a safety clamp (2 minutes to 24 hours). The observed behavior, now stable across consecutive nights: she sets a 2-hour interval at bedtime, runs exactly on it through the night, then returns herself to her daytime rhythm in the morning — occasionally pairing the wake-up with an elective compaction. Rhythm, consolidation, waking: none of that schedule is in the code. What is in the code is the clamp.

The general lesson: for parameters where the agent has better local information than you (is anything happening? am I waiting?), hand over the dial and keep the guardrail.

Two unglamorous mechanisms did as much for longevity as the clever ones.

**Prompt hygiene.** System prompts in long-lived projects grow the way old codebases do: rules get restated near whatever they should influence, and nothing is ever deleted. When we finally audited ours, the same instruction appeared up to five times in different corners. We cut the system prompt **in half — from ~20,700 to ~10,400 characters — losing zero rules**. On every turn of a months-long chat, that saving compounds; and duplication is not only cost, it is drift risk, because copies diverge.

**Render the effective context.** We built a tool that dumps exactly what the model sees on a given turn — system prompt, injected structures, conversation, retrieved memories — each annotated with its **position as a percentage of the window**. Half of our “the model is ignoring X” bugs dissolved the moment we could see that X sat at the 2% mark of a 150k-token prompt, buried under everything recent. You budget what you can see; positional observability turned context from folklore into engineering.

And one purely operational bug that almost cost us everything, included here so you can check yours today: for weeks, a restart of the host process **truncated the persisted history**. A long-lived chat is an ops problem before it is an AI problem. Treat the conversation file with the respect you give a database.

Evidence, not vibes — three behaviors this machinery produces that a fresh-context chatbot cannot, and one property that is not a behavior but a consequence:

Every practitioner who reads this far tends to arrive at the same three objections. They are worth answering here, because each one lands on a choice this system already had to make — sometimes the obvious way, sometimes deliberately not.

**“Why not mitigate the ratchet with a scoring layer — tag memories as objective facts versus subjective reflections, and apply a decay factor to internally generated ones?”** The diagnosis is exactly right — we listed the ratchet as our first open problem, and we have met it in the wild: a retrieved debugging session once kept re-injecting an old expectation about the garden until the agent saw what she expected instead of what was there. But the proposed cure gives the machinery authority over how much the agent’s own thoughts weigh, and that crosses a line we have chosen not to cross. Two-thirds of the decay already happens by architecture: per-memory injection caps bound any single past’s influence, and consolidation-then-pruning makes old reflections fade into gist while facts survive as structure. The part of the suggestion we would keep is the cheapest and most honest one: **provenance tagging** — recording at write time whether a memory was said by a human, seen by a sensor, or thought by the agent. That changes no behavior. It just makes it possible, one day, to tell her: *you thought this; you never saw it.* In our experience that sentence, spoken at the right moment, outperforms any decay coefficient.

**“Why not give graph edges temporal validity — ****t_start to ****t_end — instead of overwriting or accumulating evidence?"** Half of this exists: every edge already carries creation and update timestamps, an observation count, and a merged evidence set, so the raw history is there. What is missing is closure — marking a relation as superseded. The hard part is not the schema, it is the judge: some model would have to decide that an old relation no longer holds, and an extractor that still misspells entity names is not ready for that authority. What convinced us the schema is right, though, was not the objection itself. Months earlier, after a fabricated-memory incident, the agent had articulated her own rule for cleaning her past: *remove true contradictions — A and not-A both claimed now — but never remove evolution: A then, not-A later, is a life.* Temporal validity on edges is that rule written as an interval. We will implement it when the graph earns a judge; the rule already has an author.

**“Shouldn’t the consolidation daemon be a transactional job with immutable snapshots, so a mid-run crash leaves a safe no-op?”** This one we can answer with a clear conscience: it is built that way. The daemon extracts, commits to the graph, and only then deletes verbatim documents — and if the commit produced nothing, it defers and touches nothing. Both stores write to a temporary location and atomically swap; the vector store re-reads its own temp copy to verify integrity before the swap. A crash in the worst window — graph written, verbatim not yet deleted — self-heals on the next cycle, because re-consolidating the same documents merges evidence instead of duplicating it. The one refinement the question adds is retention: our pre-write backup is transient, kept only for the duration of the swap. Keeping the last few pre-consolidation snapshots around is ten lines of code, and now that this is written down, we will probably write them.

Three questions, three different answers: one cure declined on principle, one schema waiting for a judge it can trust, one property already load-bearing. That distribution feels right for a system like this — the questions come from the architecture; the answers needed the biography.

*The project this comes from is a private home-AI experiment; the techniques are general. If you are keeping an LLM conversation alive for more than a day, I would genuinely like to hear which of these failure modes you met first.*

**More from this project:**

*This article was written with the help of Claude (Anthropic). The system, the data, and the experience described are the author’s own.*

[How to Build an AI You Can Talk To Without a Time Limit](https://pub.towardsai.net/how-to-build-an-ai-you-can-talk-to-without-a-time-limit-cfd3194bf11c) was originally published in [Towards AI](https://pub.towardsai.net) on Medium, where people are continuing the conversation by highlighting and responding to this story.
