Skip to content

Parts, relationships & memory ​

Kuru's persistent unit is a part. A part has a stable identity, a role, and its own history. It can send a message directly to another active peer; there is no model that supervises every other model call.

The runtime schedules those calls and enforces limits on rounds, tools, and concurrency. The provider performs inference. This keeps the structure of the pool separate from the model you choose.

Memory has boundaries ​

ScopeWhat it holdsWho receives it
Shared conversationYour prompts and public responsesActors given that session context
Part memoryA part's private historyThat part
Relationship memoryThe history of a particular groupThat relationship and its authorized members

Joining a relationship does not merge the members' private memories. One part's private history is not silently concatenated into another part's prompt.

You can inspect identities with /parts and their stored conversation history with /memory NAME_OR_ID. /notes NAME_OR_ID and kuru memory notes ID read the separate durable notes namespace. The notes view returns chronological newest notes plus its requested limit and truncated flag, so it does not imply a full export. The human user can inspect private memory; the separation governs what the actors receive.

Relationships ​

Two to four unique active parts can form a protection, polarization, or alliance relationship. Parts may propose these relationships during a turn. You can also activate one explicitly:

text
/parts
/relate alliance FIRST_ID,SECOND_ID

Use IDs from /parts. A relationship has an identity derived from its kind and membership, independent of member ordering. Its history survives after it stops speaking.

A relationship can become the voice you are talking to. Use /focus NAME_OR_ID to select a speaking identity and /focus auto to return to contextual selection. Names must be unambiguous; an ID is useful when several parts share a role.

Project scope ​

Histories persist across sessions within their project and framework scope. Project identity comes from the canonical directory path: opening the same directory through a symlink uses the same project. Another directory has a separate scope.

Changing frameworks selects a different topology. It does not give the new pool unrestricted access to other identities' private histories. Jungian Collective memory is also project-scoped.

Local storage ​

Kuru stores durable state in a separate Dolt database for each project:

text
$XDG_DATA_HOME/kuru/memory/<canonical-project-hash>/

If XDG_DATA_HOME is unset, the data directory is ~/.local/share/kuru on macOS/Linux or $env:LOCALAPPDATA\kuru on Windows, with $env:USERPROFILE\AppData\Local\kuru as its Windows fallback. --data-dir or KURU_DATA_DIR chooses a separate directory. Keep it outside the tool workspace and restrict access as you would any chat history.

Kuru includes its verified native Dolt engine and license notices in the executable. First memory use extracts them locally, including when offline, and runs the new engine once to confirm its exact version before using it. Later runs read the complete cached payloads for their pinned digests, revalidate their checked names and identities and reuse the cache at tools/dolt inside the data directory without running the engine again for a version check. An intact cached engine that cannot run on this system is reported when its database fails to start. Independent warm opens verify concurrently; the installation lock is reserved for missing-cache extraction and publication. No separate engine installation or runtime download is needed. memory.cache_dir selects another extraction directory. Corrupt existing caches fail before execution and remain preserved.

While memory opens, Kuru shows one plain sentence about what it is doing, such as "Opening this project's memory…", "Getting Kuru's memory ready on this computer…" on first use, "Creating this project's memory…" for a new project, "Upgrading this project's memory…" after an update, or "Waiting for another copy of Kuru to finish with this project's memory…" while another copy of Kuru still holds it. On a terminal the sentence is rewritten in place and erased when memory is ready; when standard error is not a terminal, each new sentence is written once on its own line. An interactive session whose standard error is redirected but whose standard output is a terminal shows the sentence on that terminal instead, rewritten in place and erased before the interface opens. It is not a timer or proof that a step succeeded. Command output, including JSON, remains on standard output and never receives the sentence.

The first conversation/runtime command (kuru run, kuru dream, kuru undo-dream, the TUI, or kuru serve) that opens a writable project store also shows one short local storage notice after the store is actually ready. It names the escaped managed directory and links the available controls: kuru memory notes ID, kuru memory export --format json --output PATH, kuru memory forget ID --note SEQUENCE, and kuru memory purge --help. Kuru records that the notice was shown only after stderr or the first TUI frame completes. It is not provider input or peer chat. Memory and chat do not expire automatically; selected-note forgetting changes current memory while retaining earlier Dolt revisions.

The authenticated SQL sidecar runs only while its owning Kuru process needs it. Existing SQLite data is imported from a consistent snapshot; the original and snapshot remain preserved.

Messages can contain ordered text and structured tool-call/result blocks. Schema 3 labels old rows as literal text and new typed rows with an explicit content format; JSON-looking old messages remain text. Schema 4 retains compact indexed operation receipts across later writes, while preserving old candidate branches on their historical schema. Older Kuru binaries that do not support schema 4 refuse the upgraded store instead of downgrading it.

Schema 5 retains physical session identity on new transcript and actor-history rows while leaving ambiguous legacy rows unattributed. It also adds strict context-summary and cursor records for bounded same-view compaction. Existing session-scoped admission permits different conversations to run together while keeping one driver per session. Policy-selected continuity admits bounded same-actor current summaries from other sessions through own-history visibility, while keeping the current session's cursor and raw suffix separate. Older shared summaries are omitted whole when needed for model fit; foreign raw rows and producer-private reasoning sidecars are never projected. Older binaries refuse schema 5 rather than assigning or dropping session provenance.

JSON and Markdown memory exports use export format version 3 and include each message's optional session identity and content-format discriminator, plus strict context-summary and cursor records. Unattributed legacy rows retain a null session identity. Export consumers should check those versions before interpreting the stored content. This representation does not enable image input or store native encrypted reasoning.

Use kuru memory status to inspect the store and current revision, kuru memory history to list committed changes, or kuru memory notes ID --limit N to read one identity's current-mode notes from an existing live store. Exact retained part and relationship IDs remain readable after inactivity; names and roles use active identity resolution. Notes limits are 1–1000, defaulting to 100. Dream candidates stay private until promotion. Undo adds a compensating revision and preserves later conversations.

Notes output includes a stable sequence and stored role for each current row. kuru memory forget ID --note SEQUENCE explicitly removes one selected active notes row and commits that change as a new revision. It does not alter a conversation, other notes, or earlier revisions. This is active-memory control, not secure erasure, and Kuru does not expose a history-recovery command.

Use kuru memory purge --yes only when you intend to remove one project's managed local Dolt memory and revision history. It also removes recognised managed recovery copies and suppresses that project's automatic legacy SQLite re-import. It retains original/shared legacy SQLite inputs and migration snapshots, exports and backups, other projects, engine cache, and lock objects. It refuses a live owner, never kills another process, and does not promise secure erasure or rewrite copies outside the managed project store. After memory is gone, it removes that project's bounded diagnostics ring. An incomplete purge is resumed only by rerunning the same explicit command against its recorded identities.

kuru memory export reads every application message, state, context-summary and context-cursor row from one captured committed main revision. The JSON default and Markdown option preserve the same rows and a manifest with revision, schema and row counts. Previous revisions, candidate branches, uncommitted rows, operations and schema tables are excluded. Export is provider-free and refuses fresh stores, legacy import, and overwriting an output path; it is not a history-rewrite, purge, or secure-erasure operation.

The export is full-project data for its invoking owner and can contain producer-private state, including settled provider reasoning summaries. Keep its output private. Transcript, peer context, fork presentation, and session export do not project that state. During an active selected-speaker turn, the existing TUI may show a bounded transient text-only reasoning preview; it carries no provider coordinates, clears with the turn, and is never a durable record. The producing actor can use private state only through a policy-selected replay or compaction path; it is never injected into every request.

History follows the Dolt commit graph from the current revision toward older ancestors, with a stable hash tie-break rather than wall-clock ordering. Kuru reconciles an interrupted write against its durable receipt before it continues, so it can distinguish no pending operation, a completed operation, and one that did not commit. It answers from the receipt as soon as it exists, and otherwise waits for the interrupted write to finish, within the existing operation deadline.

Current writable branches retain compact internal operation receipts for exact lost-reply reconciliation. Historical schema-1-through-4 branches keep their older receipt shape. Kuru reclaims a dream candidate only after its promotion or explicit abandonment is durably resolved. Unresolved candidates, conversations, notes and reachable revisions do not expire automatically. The bundled engine performs bounded, growth-triggered storage maintenance while Kuru owns it, but retained history can continue to grow. This maintenance is not secure erasure. If a private install stage cannot be removed after the engine is published and verified, Kuru keeps that stage with a receipt and collects it on a later open; leftover stages are counted, and a sweep that leaves at least a small cap of them behind is reported to diagnostics. An installation that stops before publishing, after an error or a cancelled open, is handled the same way: a stage it cannot remove is receipted as unpublished and reported to diagnostics, and the receipt and diagnostic name the stage. An error the installation itself returns names it too; a cancelled open returns none, and an internal failure such as a crashed worker may not. Kuru records a retained stage before it releases the installation lock, so another installer never finds an unrecorded one. A failed activation instead keeps its stage deliberately as evidence and names it in the error. No stage whose removal is still uncertain is deleted. If even the receipt cannot be written, diagnostics say so, as does a notice on standard error when an inspection command's own open published the engine: Kuru could not remove some leftover setup files and will not retry, and they have to be removed by hand when no copy of Kuru is running. That stage is never collected automatically.

An operating-system writer lock prevents two Kuru processes from overwriting the same project's topology. Read-only session listing remains available.

Migration and backups ​

Close older Kuru sessions before the first launch with Dolt. Kuru imports the current project's rows from memory.sqlite3, verifies them, and preserves the original plus a complete snapshot under memory/legacy/. Other projects are imported when opened. After migration, older Kuru versions write only to the old SQLite store, so avoid using them with the same data directory.

Memory-owned directories must be private. On macOS and Linux, Kuru names a rejected real current-user-owned directory with group or other access and asks you to restrict that exact path to mode 0700. This includes project data, managed Dolt cache and version directories, cold probes, installation destinations, and private server directories, whether or not legacy SQLite is present. It never changes access modes or offers that remedy for a link or foreign-owned path. On Windows, correct the project data directory's owner-only access in native file security settings before retrying; managed runtime and server directories retain native filesystem diagnostics rather than receiving a Unix mode instruction. Kuru leaves the rejected directory and its permissions unchanged; correct that exact path before retrying.

An interrupted import can resume after validation. Partial imports are stopped and preserved under memory/interrupted/; a failed import never becomes the active store. Keep the original and snapshots until you have checked every project you want to retain.

New project stores are created by copying a pre-built, schema-only template instead of running every schema upgrade. The template lives beside the engine in its cache, under <engine version>/templates/, and is built once per machine, engine and schema. It holds only schema, migration receipts and a fixed placeholder identity, never project data or credentials, so every project sharing the cache can use it and kuru memory purge leaves it in place. Each copy takes its own identity and credentials on its first start and shares only schema history with other copies.

What the first launch pays: the first new project on a machine, and the first after an update that changes the schema or the engine, builds the template before copying from it, which takes about as long as building a store directly did. Every later new project opens faster, because it skips the schema upgrades. A project that imports older SQLite data, or a configured development engine (memory.dolt_binary), is still built directly. Whichever way a new project is created, including while the first launch builds the template, Kuru shows "Creating this project's memory…" until it is ready.

If the template is busy (another Kuru process is building it) or cannot be used, the new project is simply built directly, with a warning in the memory service log; you do not need to do anything. If a copy turns out to be damaged once its own database has started, that open fails with a template error, nothing appears at the project's path, and the damaged template is moved aside: opening again builds a fresh template. The unready copy is set aside under memory/interrupted/, at once if its database had started serving and otherwise when you open the project again, without starting it; a copy interrupted by a crash is set aside the same way. If the first launch's template build fails, or copying the project from the template it just built fails, that open fails with that error and opening again tries again (a copy that finds the new template damaged also moves it aside); Kuru never runs the schema steps twice in one open. See memory storage for the details. If Kuru keeps warning that it cannot read a template, delete that template's directory under templates/ while Kuru is not running; it is built again once.

Kuru also applies compatible database schema upgrades automatically when a writable project opens. Each upgrade is prepared on an internal isolated branch and is fast-forwarded only after its committed receipt and schema validate. Interrupted attempts are retained for inspection instead of reset or deleted. Read-only access reports an older supported schema without changing it; an unknown or inconsistent schema stops safely. The database schema version is separate from the format-1 activation record, database identity record and supervisor protocol format, and older dream candidates remain historical rather than being rewritten.

Startup also stops if retained migration attempts are ambiguous or exceed its bounded inventory. It keeps that history and reports the condition for recovery rather than deleting or resetting branches.

Schema 8 records each published upgrade in the same commit that publishes it. Later opens check a recorded upgrade branch against its record and main's history, without checking the branch in full each time. A record that disagrees with the store stops the open without changing anything. A branch without a record is still checked in full. The first writable open after updating upgrades an existing project once: it checks every retained branch in full one last time, records the ones it accepted, then reopens the upgraded store. Until that writable open, a read-only command reports memory schema version 7 requires writable upgrade to 8 and changes nothing, just as it does for any pending schema step. Projects created after the update start at schema 10.

Schema 9 adds a version to each project state row. Existing values keep their exact bytes and start at version zero; every overwrite advances the version, including equal-value writes and turn checkpoints. Conditional publication compares all expectations and writes its entire batch in one transaction. A stale expectation leaves values and revision history unchanged. Dream writes advance only their candidate's versions until exact promotion. Historical views keep their schema, and older binaries refuse an upgraded schema they do not understand. Concurrent conversation admission remains gated.

Schema 10 stores each mode's membership separately from its identity reports. Membership changes check the version they loaded; ordinary reports replace only that identity's last report. Focus belongs to the session. Dreams and undo change membership without replacing current reports or another session's state, and retired identities remain inspectable.

The upgrade materializes the latest legacy topology and preserves its original bytes. Malformed input or conflicting split records stops the upgrade without publishing a partial result. Legacy project-wide focus is left unassigned. Complete topology reads use a single committed revision, with bounded pages for larger inventories, so updates during inspection cannot mix old and new records.

Use kuru memory backup PATH to capture a restorable native image while other sessions continue writing, and kuru memory verify PATH to check it through an independent native restore. Images retain revision history, candidates, sessions, private memory and usage, so keep them private. They exclude credentials, trust grants, live claims, service endpoints and runtime caches.

kuru --data-dir NEW_DIRECTORY memory restore PATH requires an absent target. Restoring from another canonical workspace also requires --remap-project. The target receives fresh ownership while retaining its checked history namespace. Supported historical schemas migrate in a private stage. Dirty main and usage roots are preserved through appended staged and working snapshots before writable activation; other refs and the original image remain unchanged. Keep the image until you have checked restored sessions. Do not copy a live .dolt directory or remove a held lockfile. See the contributor backup and recovery guide for publication, cancellation and retained-stage behavior.

See sessions and dreaming for resuming a transcript and changing the pool's membership.

Persistent peers. Deliberate tools. Your terminal.