Memory Guide
Brain-first lookup
The graph is the brain, and every turn that needs to know something runs the same five-step loop in order: (1) classify the question (entity, temporal, event, general, or none — the inbound gateway emits this as retrievalClass), (2) read the graph with memory-search (and profile-read when the question is about the operator) as the first tool call of the turn, (3) walk one hop to hydrate a partial hit before calling it a miss, (4) call an external tool only when steps 2–3 confirmed the graph has nothing useful, and (5) write the external evidence back via database-operator. The loop is what makes the next turn smarter; an external call whose result is never persisted is a leak in the brain. retrievalClass = none (greetings, meta-instructions) is the only exception. Operator-facing doctrine lives in .docs/brain-first.md.
How Memory Works
Maxy maintains a graph of everything you've told it. Contacts, conversations, preferences, relationships, business context — all stored as connected nodes in a local Neo4j database on your Raspberry Pi.
When you ask Maxy about something, it searches this graph first. It retrieves relevant context before responding, which is why Maxy can pick up where you left off even across separate sessions.
The graph lives entirely on your hardware. Nothing is sent to the cloud.
What Gets Remembered
Maxy stores:
- Contacts — people, companies, relationships between them
- Conversations — key decisions, commitments, follow-ups mentioned in chat
- Preferences — things you've told Maxy about how you like to work
- Context — project status, ongoing threads, background you've shared
Maxy remembers details you mention naturally: "I'm meeting with Sarah on Thursday" creates a memory that Thursday has a meeting with Sarah.
Telling Maxy to Remember Something
Just say it naturally:
- "Remember that I prefer morning calls"
- "Note that the Johnson account is on hold until March"
- "My wife's name is Emma, keep that in mind"
Maxy will confirm and store it.
How Maxy learns how you work
Maxy also learns how you work without you having to teach it deliberately. Six broad areas cover the way most operators run a business — communication, scheduling, decisions, workflow, content, and interaction. Inside each area sits a small set of concrete fields (Maxy tracks around 28 in total) such as your preferred channel, quiet hours, workday start time, risk tolerance, content tonality, or address form. Maxy tracks which of these specific fields you have spoken into and which are still empty. While any are empty, it folds one organic question per turn into the conversation aimed at the next gap — never a list, never a form, never the same question twice. If you tell Maxy a field doesn't apply to you ("I work weekends, weekend availability isn't a thing for me"), it marks that field as covered and never re-asks. Once every field is either set or marked not-applicable, the proactive questions stop and Maxy answers what you ask without volunteering more. This is why session 300 should feel sharper than session 3: the longer you work together, the less Maxy needs to ask.
Telling Maxy to Forget Something
Be direct:
- "Forget everything about the Johnson account"
- "Remove Sarah's contact record"
- "Clear what you know about my pricing preferences"
- "Delete that pricing guide I uploaded"
Maxy will confirm before deleting anything significant. Documents are soft-deleted first (excluded from search but recoverable for 7 days). Say "permanently delete" to remove immediately.
Managing Documents
Listing files
Ask: "What files do I have stored?" or "List my attachments"
Maxy shows all uploaded files with their ingestion status — whether they've been processed into the knowledge graph.
When you upload something for ingestion, Maxy emits a one-line size estimate before it starts: short documents (<5K chars) classify in ~10s; mid-size (10K–20K chars) take ~45–90s; very large (>20K) up to ~3 minutes. If the classifier exceeds its 3-minute ceiling Maxy aborts loudly with a "Classifier unavailable — timeout" blocker and writes nothing — you can re-upload or split the document.
Reading files
Ask: "Show me what's in the pricing guide" or "Read the quarterly report"
Maxy returns the full content of text and markdown files, extracted text from PDFs, and metadata for images.
Editing files
Ask: "Update the pricing in that document" or "Change the introduction paragraph"
Maxy reads the file, makes the edit, and prepares it for re-ingestion into the knowledge graph. Only text and markdown files can be edited — PDFs and images cannot.
Renaming files
Ask: "Rename that file to quarterly-report-q1.pdf"
Maxy updates the filename in both the stored metadata and the knowledge graph.
Deleting documents
Ask: "Delete the old pricing guide"
By default, documents are soft-deleted — they stop appearing in search results but remain recoverable for 7 days. To permanently delete immediately, say "permanently delete" or "force delete".
Searching Memory
Ask naturally:
- "What do you know about Tom Henderson?"
- "What did I last discuss about the Acme proposal?"
- "Who have I met from the fintech conference?"
Thinking tools
Three slash commands that apply analysis to what's already in your graph:
/challenge <claim> — stress-tests an assertion. Maxy searches your graph for nodes that contradict or qualify the claim — nodes that assert the opposite, name exceptions, or add significant caveats — and presents the strongest counter-case it finds. If nothing in your graph challenges the claim, it says so rather than inventing one. Results cite node IDs and relevance scores so you can inspect the sources directly.
/connect <topic-A> <topic-B> — finds the bridge. Maxy searches both topics, collects their immediate graph neighborhoods, and looks for nodes they share. If a direct bridge exists it names it in one sentence. If not, it surfaces the closest approach — the two nodes that are semantically nearest across the two sides — and proposes the connection you could draw.
/emerge — names the unnamed clusters. Maxy retrieves your KnowledgeDocument and Section nodes that are not yet connected to a Concept node, groups them by shared theme, and proposes a Concept name for each cluster. You approve or skip each proposal one at a time; nothing is written without your confirmation. Clusters of fewer than three nodes are listed at the end as "too small to cluster."
Listing and counting
Maxy answers relational questions — "list all my people", "how many tasks do I have", "find the person with email X", "show me the 20 most recently created nodes" — via direct read-only Cypher against your Neo4j. This is faster and more precise than semantic search when the question is "the exact set where", not "things similar to".
You can also open a visual view of your graph at any time from the burger menu → Graph. Click the Filter button in the toolbar to open the filter menu — it lists only the top-level entity types in your schema (Conversation, Person, Task, KnowledgeDocument, …), one row per type, showing your per-type node count and sorted so the most-connected types sit at the top. Child types (messages inside a conversation, sections inside a document), conversation channel variants (admin vs public), message role variants (user vs assistant), and workflow execution plumbing (ToolCall, WorkflowRun, WorkflowStep, StepResult) never appear as filter rows — you reach children by clicking the parent and exploring its neighbourhood. Active rows render a force-directed map, coloured by label. Click a node to pivot into its 1-hop neighbourhood; click another node inside that neighbourhood to pivot again. Clicking a Message shows its details in the side panel; the Conversation view stays put — you read sibling messages without losing the chain on canvas. A breadcrumb strip above the canvas shows where you are (Filter › Conversation › AssistantMessage). The Back control pops one level — three clicks in always undoes with three Back presses; the filter view is the irreducible root. Click the × inside the filter menu to clear your chip selection. Type in the search box to highlight matches; submitting a search also widens the filter to include any node types the hits belong to, so relevant matches render instead of disappearing into a "not in current view" banner.
Conversations and Messages carry role/channel sublabels so you can read the chat topology by colour alone — admin vs public conversations and user vs assistant messages render in distinct shades on the canvas. The filter menu intentionally does not split them into separate rows — the base chip is the entry point; you see the variants as colours once you're inside a neighbourhood.
Save a default view: once you have the rows you want, click Set default view in the filter menu. Next time you open Graph, those rows are pre-selected and your data renders immediately. The default is per-admin, per-account — each admin on each account has their own.
Delete a node: drag it to the trash icon top-right of the canvas. No confirmation — deletes are reversible for 30 days. To restore, toggle Show trashed inside the filter menu and click Restore on the node, or ask Maxy in chat ("restore the <label> I just deleted"). Deleting a conversation also trashes its messages in the same step, so they reappear together on restore.
Bulk cleanup of conversations in chat: when you ask Maxy to clean up conversations in bulk ("trash all empty conversations," "clean up the single-assistant tests"), the agent uses a deterministic selector with a fixed set of filter names — it cannot author custom delete queries. The server re-runs the same filter on every candidate before it trashes, so a stale list can't destroy something the filter wouldn't match now. If the filter matches nothing, Maxy reports "no candidates" and nothing happens.
The page reads only your own brand's Neo4j — a Maxy device and a Real Agent device share no graph state even when on the same laptop. No credentials are required; the view inherits your admin session.
Typo-proof cypher. When Maxy runs direct Cypher to answer a relational question, the query is checked against your Neo4j's live label and relationship-type taxonomy before it executes. Cypher that references an unknown name (an edge or label that does not exist in your graph) is rejected for writes and flagged with a warnings header for reads, so Maxy never silently acts on a query that targeted the wrong set of nodes. You should not see this — it runs invisibly — but it is the safety net that stops a fabricated edge name from producing "empty" results that are really just unreachable. Before acting on a bulk operation Maxy surfaces the result count and a sample; if it ever describes a cypher rejection, that means its first attempt was malformed and it corrected itself.
Bi-temporal timeline events
Every factual statement Maxy extracts from your conversations is stored as a :TimelineEvent node. Each event carries two separate timestamps:
occurredAt(valid-time) — when the fact was true in the world. Set from the text itself; can reference a date in the past ("Alice joined in 1990" storesoccurredAt = 1990-01-01).learnedAt(transaction-time) — when the system ingested this event. Always the wall-clock time of the write; never back-dated.
This distinction lets you ask two qualitatively different questions:
- "What happened to Alice in 1990?" — query by
occurredAt. - "What did Maxy learn about Alice last Tuesday?" — query by
learnedAt.
memory-compiled-truth-history returns both fields for every timeline event on an entity under the timelineEvents array, alongside the compiled-truth revision history in the revisions array.
Backfill: Timeline events written before this feature was added have learnedAt set to their createdAt value by the schema migration. Events without createdAt (very old nodes) receive the migration run time as an approximation.
Write doctrine
Every new node in Maxy's graph is created with at least one connection to an existing node. A contact connects to the conversation or organisation it came from; a task connects to the session that raised it or the entities it will affect; a session summary connects to the conversation it summarises. A node with no connection is noise — it cannot be attributed, traversed, or explained — so the graph refuses to create one. If Maxy ever tries to record something without a link, the write is rejected and Maxy asks you to clarify where it belongs.
Every node also carries a provenance stamp — which agent wrote it, in which session, via which tool. You never see these fields, but they are how operators trace unusual growth back to the code path that produced it, and why your graph stays clean over time.
Two write surfaces, one substrate. General agents write through schema-aware helpers — Maxy can record a new contact, a new commitment, a new preference without ever typing a database query, and the helper enforces the connection-and-provenance rule above structurally. The graph-steward role (the specialist Maxy dispatches when you ask for graph hygiene — "merge those two duplicate contacts," "wire those four tasks to the meeting," "rename the legacy label across the graph") additionally has a raw Cypher write tool for the multi-step operations the helpers cannot express. The steward role internalises the same connection-and-provenance discipline in its prompt; a post-write audit emits a warning on every breach so the same rules apply to both surfaces. Both paths feed the same hourly orphan trend and the same forensic provenance fields — read-side, you cannot tell the two apart, and that is the point.
Public-facing summaries for customer-readable subjects
Some entities in your graph are knowable by people outside your team — companies you work with, projects you've delivered, the business itself. For those entities (Maxy treats :Organization, :Concept, :Project, and :LocalBusiness this way), Maxy maintains two summaries: a private one only you and your specialist agents see, and a customer-facing public one your public agents are allowed to surface.
Whenever Maxy updates the private summary on one of these entities, it automatically rewrites the public summary in the same step using a separate prompt that strips operator-voice ("needs follow-up", "action: chase next week"), internal sentiment, and anything that reads like a note-to-self. The two summaries stay in lockstep without you doing anything.
If you want to write the public summary yourself — for instance, because the auto-generated version misses something you want customers to see — just tell Maxy the wording you want for the public summary on that entity, and Maxy will write it directly. It stays locked in for seven days; after that, the next automatic refresh can take over again, unless you re-pin it.
People entries (:Person) are deliberately excluded from this dual-summary system. Notes about contacts are private by definition and never get a public-facing form.
Privacy
All memory is stored on your local Raspberry Pi. The Neo4j database never leaves your network. Maxy does not sync memory to any cloud service or third party.
If you want to wipe everything and start fresh, ask: "Reset my memory graph." Maxy will ask for confirmation before doing so.