From a Local Chat Client to a Cognitive Environment
A locally owned place for conversation, memory, knowledge and planning—and how a question about a Mac chat client brought years of separate work into the same design.
A conversation on my Mac, a terminal session, and a planning tool could all work with the same accumulated experience: what we discussed, what we tried, what changed our minds, and where the evidence lives. The models and interfaces could change while that history remained ours to examine and build upon.
That is the shape Sofie, my AI collaborator, and I arrived at today: a locally owned cognitive environment, bringing conversation, memory, conceptual knowledge, planning and analysis into a common architecture. We have a design to investigate. The individual projects have histories of their own; their integration is still ahead of us.
Two features of the drawing carry much of the argument. There are two routes into the services: an inexpensive native path and a coordinated path through the Composite Cognition Dispatch Protocol, or CCDP. Further down, the existing ontology stores remain authoritative. Connecting the environment does not require moving everything into a new database.
I started by asking for a good local chat client for OpenRouter.
The database question underneath the interface
I wanted a useful interface on macOS, locally operated, with access to remote models when I chose to use them. Local ownership of the application and its records was the goal; local inference could be a separate choice.
LibreChat became interesting because it offered a graphical surface we might adapt and connect to other tools. It also brought a stack I was less enthusiastic about adopting wholesale. Before long, we were discussing whether its MongoDB persistence could be replaced.
That question needs care. LibreChat's architecture documentation identifies MongoDB as its database and locates database-specific shared logic in packages/data-schemas. Those package boundaries give us somewhere to start investigating. They do not establish that the database is a replaceable component behind a neutral interface.
Our discussion of Mongoose made the difficulty clearer. When application code relies on a document model's defaults, validation, hooks and query behaviour, those expectations become part of the persistence contract. Reproducing the stored fields would cover only part of a migration. Users, presets and other application state would also need attention beyond a first experiment with conversation history.
An interface expressed in terms of conversations, messages and attachments began to look more useful than a decision about the replacement engine. The application should be able to ask for a conversation or append a message without knowing whether the implementation uses Mongo, Lance or something else.
I already had reasons to want that boundary. My work includes Rust MCP infrastructure, graph systems built around petgraph, LanceDB retrieval, and a great deal of DuckDB analysis of local files and JSON. I wanted those capabilities available around a conversation. I also wanted room for a Rust terminal interface built with ratatui, where graph neighbourhoods and prior decisions might be as prominent as the latest message.
A database chosen to satisfy one chat application's expectations would be answering too small a question.
Letting several tools work on the same material
There were three plausible places to seek coherence. A single multimodel database could own the records and provide the operations. Several engines could work over shared durable data. Or a service could present a common query boundary over stores that remained physically separate.
We considered SurrealDB in the first role, Lance in the second, and an Arrow/DataFusion layer in the third. These were architectural possibilities to compare, with different integration costs. SQLite and PostgreSQL remained sensible answers to narrower operational needs.
Lance held my attention because of the combination it suggested: durable records that could feed retrieval, graph computation and analysis. In that picture, LanceDB would supply retrieval; petgraph would support graph projections and algorithms; DuckDB would let me ask analytical questions of the corpus. Lance Graph was another candidate to investigate, while keeping the graph engine replaceable.
There is a concrete technical foothold here. DuckDB's Lance extension documents direct reads and writes of Lance datasets, along with vector, full-text and hybrid-search functions. That gives the shared-data idea substance. It leaves us to establish how particular engines, indexes and readers would agree on versions and freshness in our own system.
The distinction matters when a conversation changes. If I correct a message, its text, embedding, graph projection and analytical view may not all update at the same instant. Sharing a storage format does not determine when a reader may call the correction visible. Derived data still needs maintenance, and some views may require copying or transformation.
DataFusion offers another useful possibility: an extensible Rust query engine using Arrow, with custom data sources supported through TableProvider. We could use it where queries need to span different stores. Its extension points make that worth exploring; the actual questions we need to answer should determine how much integration machinery we build.
For writes to the new corpus, the direction we favoured was one Rust service with explicit ownership. LibreChat, a TUI and other tools would submit domain operations to that service. Analytical work could read snapshots and write its own derived products. Existing authoritative graph systems would keep their own ownership.
This gives retries, ordering, revisions and durable acknowledgement a defined home. We would still have to design each of them. It also leaves room for a small transactional store where frequent operational updates fit better than corpus storage.
At this point, the sketch could have become a fairly conventional data-infrastructure project. The larger change came from recognising what was already waiting to connect to it.
The knowledge was already there
For roughly two years, I have been extracting concepts and building graph knowledge databases, with the NeON methodology informing the work. That effort spans music theory, advanced mathematics, programming languages and other subjects. The conversation was taking place alongside an existing body of conceptual knowledge.
An earlier article, Graph Theory in LFE: A Knowledge Graph of Erlang Itself, used an Erlang concept-card corpus to explore what graph operations make possible. A collection of source-derived cards can support questions about paths, dependencies and groups of related ideas. Its relationships are part of what makes it useful.
That history changed the meaning of the new storage proposal. Moving all the graph data into Lance would require a separate argument. We could begin by giving episodes, assertions and plans stable references to concepts in the existing ontology network.
Consider a conversation about event sourcing. Its messages might live in the new corpus, with an embedding used for retrieval. A concept reference could connect the episode to an authoritative definition, relevant relationships and source material elsewhere. Rebuilding the embedding or moving the message file should leave that concept's identity intact.
The same approach could connect a discussion of voice leading to music-theory knowledge, or an account of a microscope adjustment to the concepts needed to understand it. Each episode retains its circumstances. The conceptual network provides ways to find and interpret it beyond the words that happened to occur in the conversation.
This brought several meanings of “memory” into view:
| Kind of material | What it needs to preserve |
|---|---|
| Conceptual knowledge | Definitions, relationships, modules and alignments. |
| World assertions | Claims about particular things, with evidence and temporal scope. |
| Episodes | Events and conversations recoverable in their original context. |
| Procedures and plans | Ways of acting, including preconditions and expected effects. |
| Cognitive traces | Observable retrievals, tool use, revisions and outcomes. |
A definition of a mechanical stage and a record of what I adjusted on mine have different jobs. So do a proposed migration plan and evidence that its steps succeeded. An environment intended to support future work needs to carry those distinctions through storage and retrieval.
It also needs to preserve disagreement. A service can own the act of recording a claim while retaining competing claims and their sources. Giving one process responsibility for writes does not give it the authority to settle every question in the corpus.
Coordination has a place of its own
The other substantial piece already in development was CCDP. Its draft specification describes how heterogeneous cognitive services can cooperate through typed requests, explicit evidence requirements and structured coordination.
That work has a connection to the supervision-tree perspective I have written about before: responsibility belongs at an explicit boundary, including responsibility for what happens when a component cannot do the job asked of it.
In CCDP, the dispatcher operates on envelopes and contracts. Services supply cognitive behaviour. The dispatcher handles routing, validation, coordination and audit without interpreting the natural-language content of a request. The specification also defines provenance composition and escalation when a service cannot meet the required evidence strength. These are requirements of the draft protocol, with implementation and integration still to be established for this environment.
A difficult memory request could benefit from that structure. It might call for retrieval, graph traversal, source checking and human review, with the results composed under explicit contracts. A planner could participate alongside model and database services. Each would contribute a capability whose role was visible.
But an ordinary memory lookup should remain ordinary. If Sofie needs the reason behind a decision we made yesterday, the memory service should offer a native operation she can use directly. CCDP would be a first-class route for work that benefits from governed composition, discovery or remote execution.
Both paths would use the same semantic objects and memory rules. Direct access would still have to respect admission, revision, evidence and access constraints. Otherwise, the simplest client would quietly become a way around the system's own guarantees.
This is why the split near the top of the diagram matters. The infrastructure should support a useful local tool at small scale and a composed workflow when the task grows. We can make those paths compatible without requiring every read to travel through a dispatcher.
Remembering without loading the library
My earlier knowledge-library reorganisation addressed a related problem at the scale of documents. An assistant refreshing its understanding of verification should be able to reach the relevant guide without loading the entire collaboration framework. The material needs meaningful entrypoints and routes between them.
The memory discussion takes that concern into a much larger corpus. I want the system to be cheap in context: able to discover broadly, then bring the right evidence into the limited working space of a model call.
A possible retrieval would begin with a compact map. It might identify a few relevant episodes, the concepts connecting them, an unresolved disagreement and handles for opening the source. The model could then ask for the parts it needed, within a stated budget.
Suppose I ask what we concluded about slowing the Y axis on the microscope stage. A useful first result might point to the discussion, the adjustment options considered, and the source spans containing the tests and conclusion. It should let us expand those spans before relying on a summary. A broader request about unfinished mechanical problems could start with a different map over some of the same material.
Several retrieval methods could help construct that map. Full-text search can recover a remembered term. Vector search can find related phrasing. Concept resolution and graph traversal can connect the question to material expressed differently. Time, project scope and evidence requirements can narrow the candidates.
This is a hypothesis about usable context, with costs we would need to measure. Graph expansion can introduce irrelevant neighbours. A compact map can omit the source the model needed to discover. Several small requests can take longer than one larger result.
The response contract therefore needs to make omissions visible. “No matching evidence,” “evidence omitted under the budget,” and “source unavailable” should be distinguishable outcomes. A concise result also needs a durable route back to its sources.
The memory-protocol effort behind this is still research work. I want its operations—retrieval, revision, consolidation, forgetting—to be informed by serious study of memory and cognitive architectures. The proposed reading spans computational accounts of memory, associative mechanisms, working memory and cognitive control. That shelf supplies questions and candidate distinctions; it does not validate a software design merely by lending us its vocabulary.
The practical test is whether those distinctions improve what the system can recover, preserve and explain. A compact answer that drops the correction is a poor memory, however few tokens it uses.
Keeping the correction in the record
Today's conversation provides its own example. An early sketch suggested putting graph data into Lance. Once the existing ontology work was properly in view, the direction changed to logical integration through stable identities, with physical migration left open.
A final summary could record the surviving preference. The episode would preserve how we arrived there: what we initially assumed, what additional context changed the design, and which alternatives remained available. That history would help a future discussion distinguish reconsidering an old option from unknowingly repeating it.
This is part of the attraction of append-oriented interaction history. Messages, revisions, tool results and annotations could produce current views while retaining meaningful changes. We might be able to reconstruct both what we believe now and what we believed at an earlier point.
There are consequential details underneath that possibility. A streamed token, a completed content block and an edited message need not be the same kind of durable event. Retried operations need identities. Deletion needs a meaning across source content, revisions, embeddings, projections and backups. Event sourcing would have to earn its complexity through the history it preserves and the workload it serves.
The same care applies when an episode becomes an assertion. A model extracting a preference from a discussion has performed an interpretive act. The resulting statement needs its source and status; repeated retrieval should not gradually turn an inference into something I supposedly said.
These requirements connect memory back to the evidence discipline in the engineering framework. A reported result, a reproduced result and an accepted result differ because the work establishing them differs. Future recall should preserve enough of that work to keep the distinction meaningful.
When memory can inform a plan
The original database question becomes more interesting when returned to this environment. Imagine asking it to help migrate LibreChat's persistence safely.
A model could formulate the task for a hierarchical task network planner. An HTN planner works with methods for decomposing tasks and conditions governing their applicability. In this proposed composition, its work could lead to code inspection, schema mapping, source-data analysis, retrieval of earlier decisions and human review.
Memory could recover why an earlier approach was rejected. Knowledge services could resolve the relevant concepts. DuckDB could help inspect the source records. CCDP could coordinate the declared service work, while the planner and other services supplied the specialised behaviour.
Stable concept identity offers a possible connection between those activities. A planning method and an earlier migration episode could refer to the same concept without living in the same store. Later execution records could show where that method worked, where it failed and which conditions mattered.
We would still need an explicit mapping from ontology concepts to planner types, predicates, preconditions and effects. A shared name does not supply executable semantics. A successful decomposition would also remain distinct from successful execution.
The possibility is that experience could become useful to action in a more structured way. Instead of repeatedly assembling a plan from a fresh prompt and whatever happens to fit in context, we could recover relevant episodes, inspect their applicability and make their role in the new plan visible.
Studying the environment through its own records
Retrieval, planning and tool use would leave another useful body of data: observable traces connecting requests, sources, results, revisions and outcomes. These records would contain what participating services expose. They would not require access to hidden model reasoning.
This brings DuckDB back into the story with a broader role than the one it had during the storage discussion. I could use analytical views to investigate which retrieval cues led to useful evidence, where plans were revised, which services escalated, and how much time or context different approaches consumed.
Those observations could help evaluate the memory design. Does concept-guided expansion improve recall on comparable tasks? Does staged retrieval preserve the evidence needed for a correct answer? When does a planner help enough to justify the additional work?
Recording a retrieval would establish that it happened. To establish that it helped, we would need outcomes and fair comparisons. Hard requests may receive more tools and still fail more often than easy ones. The traces could support experiments that account for such differences, provided we design the observations and comparisons carefully.
There is a useful convergence here. The knowledge work gives us conceptual structure. The memory research asks how to recover and revise experience. Planning gives prior knowledge a possible role in organising action. The protocol provides a way to coordinate capabilities and preserve evidence across their boundaries. Analysis gives us a way to examine the resulting behaviour.
Each project can continue on its own terms. Their connections give us additional questions we could not conveniently ask of any one of them.
A place to continue the work
The strongest commitments I take from today are ownership of the records, recoverable evidence, stable conceptual references, explicit mutation boundaries, and memory that remains useful across interfaces. Lance is a promising candidate within that design. Its suitability still depends on mutation, recovery, consistency and maintenance workloads we have not tested together.
An external memory tool could be useful before a complete LibreChat database replacement. A native client could expose parts of the corpus while more ambitious service compositions remain experimental. The architecture leaves room to learn from those smaller encounters with real work.
It also gives a more precise meaning to the continuity I want with Sofie. That continuity would come from accessible history, working conventions, project context and tools. Changing a model or opening another client would require making those materials available deliberately.
I would like to return to a composition, a mathematical question or a piece of software and recover more than the last polished answer. I want the discarded approach when it becomes relevant again, the observation that overturned it, and the source we would need to check before trusting our recollection.
The chat window is where today's exploration began. What I want to carry forward is the work we can still recognise when we open the next one.