Goal
Adopt Moraine (https://github.com/eric-tramel/moraine, Apache-2.0) as CodeWhale's long-term
agent-memory backend: Moraine ingests CodeWhale's persisted sessions losslessly and exposes them as
searchable MCP recall tools (search, search_conversations, list_sessions, get_session,
open). This supersedes the in-repo push/inject memory path (crates/tui/src/memory.rs, which
prepends a <user_memory> block into the system prompt) in favor of pull/recall via Moraine MCP.
Local-first, no prompt injection (MCP is read-only retrieval). CodeWhale keeps persisting sessions;
Moraine indexes them. Supersedes community memory PRs #3381 (@pkeging, memory tags) and
#2933 (@cy2311, hippocampal v2 — glossary/namespaces/rollback/auto-inject) — their ideas inform
the recall layer but the implementation is Moraine-backed, not in-repo.
This is scoped for v0.8.66, not 0.8.65.
Research already done (design is concrete)
Moraine fork: Hmbown/moraine (upstream eric-tramel/moraine, on main @ v0.6.2).
Key finding — the session_json ingest format already fits CodeWhale
crates/moraine-ingest-core/src/dispatch.rs::process_session_json_file reads a whole-file JSON
snapshot and extracts session_doc["messages"] — exactly CodeWhale's shape
(~/.codewhale/sessions/{id}.json → { schema_version, metadata, messages[], artifacts, system_prompt }).
It builds synthetic session_meta + per-session_message records and checkpoints by message index
(incremental ingest), then dispatches each to the harness adapter's normalize().
The fork is already half-wired
crates/moraine-config/src/lib.rs::default_sources() already contains the CodeWhale entry:
harness: "codewhale", glob: "~/.codewhale/sessions/*.json", format: SOURCE_FORMAT_SESSION_JSON.
Work items (Moraine fork)
- Add adapter
crates/moraine-ingest-core/src/sources/codewhale.rs implementing IngestSource
(harness()="codewhale", format()=SessionJson), mirroring the Hermes session handlers
(normalize_hermes_session_meta / normalize_hermes_session_message at hermes.rs:791/891).
Handle CodeWhale content-part types text / thinking / tool_use / tool_result; roles
user / assistant.
- Register in
sources/mod.rs: pub(crate) mod codewhale; + .register(&codewhale::CODEWHALE)
in registry(), and add "codewhale" to moraine-config::KNOWN_INGEST_HARNESSES
(the registry_matches_config_known_harnesses test enforces these agree).
- Generalize the synthetic builders
build_session_meta_record/build_session_message_record
(dispatch.rs:883/950) to read CodeWhale's nested identity with Hermes-safe fallbacks:
session_id ← session_doc.session_id OR metadata.id; model ← session_doc.model OR metadata.model;
session_start ← session_start OR metadata.created_at; last_updated ← last_updated OR metadata.updated_at.
Hermes files have no metadata, so it's unaffected. compose_hermes_model is a no-op for CodeWhale
(no base_url).
- Golden fixture + test mirroring
tests/hermes_session_fixture.rs, using a redacted real
CodeWhale session snapshot.
- Upstream the adapter to
eric-tramel/moraine (PR) so it ships in a Moraine release; keep the
fork in sync.
Work items (CodeWhale side)
- Wire
moraine-mcp as a recall tool source (stdio moraine mcp server) via CodeWhale's MCP
config so agents gain the recall tools.
- Config-gate deprecate the
memory.rs push/inject (call sites crates/tui/src/core/engine.rs:801
and :2996 via crate::memory::compose_block; render prompts.rs:1209; already off by default via
MemoryConfig.memory_enabled=false) in favor of Moraine pull/recall. Update docs/config comments.
Validation
moraine up ingests ~/.codewhale/sessions; MCP list_sessions/search return CodeWhale sessions
with correct session id / model / timestamps; end-to-end recall in a CodeWhale agent turn.
Known risks / gaps
- CodeWhale session files are whole-file snapshots rewritten on every save; verify the session_json
"shrank → ignore" guard (dispatch.rs:758) doesn't drop data when a new session has fewer messages
than a prior one (different file, so likely fine — confirm).
- CodeWhale messages carry no per-message timestamps (only session
created_at/updated_at);
events need synthetic monotonic ts from session start + message index (like hermes_event_dt).
tool_result content-part exact shape needs confirmation (Anthropic-style
{type, tool_use_id, content}) — handle defensively.
- Cost/tokens live in
metadata.cost / metadata.total_tokens — map into Moraine token accounting if
desired (non-blocking for recall).
Goal
Adopt Moraine (https://github.com/eric-tramel/moraine, Apache-2.0) as CodeWhale's long-term
agent-memory backend: Moraine ingests CodeWhale's persisted sessions losslessly and exposes them as
searchable MCP recall tools (
search,search_conversations,list_sessions,get_session,open). This supersedes the in-repo push/inject memory path (crates/tui/src/memory.rs, whichprepends a
<user_memory>block into the system prompt) in favor of pull/recall via Moraine MCP.Local-first, no prompt injection (MCP is read-only retrieval). CodeWhale keeps persisting sessions;
Moraine indexes them. Supersedes community memory PRs #3381 (@pkeging, memory tags) and
#2933 (@cy2311, hippocampal v2 — glossary/namespaces/rollback/auto-inject) — their ideas inform
the recall layer but the implementation is Moraine-backed, not in-repo.
This is scoped for v0.8.66, not 0.8.65.
Research already done (design is concrete)
Moraine fork:
Hmbown/moraine(upstreameric-tramel/moraine, onmain@ v0.6.2).Key finding — the
session_jsoningest format already fits CodeWhalecrates/moraine-ingest-core/src/dispatch.rs::process_session_json_filereads a whole-file JSONsnapshot and extracts
session_doc["messages"]— exactly CodeWhale's shape(
~/.codewhale/sessions/{id}.json→{ schema_version, metadata, messages[], artifacts, system_prompt }).It builds synthetic
session_meta+ per-session_messagerecords and checkpoints by message index(incremental ingest), then dispatches each to the harness adapter's
normalize().The fork is already half-wired
crates/moraine-config/src/lib.rs::default_sources()already contains the CodeWhale entry:harness: "codewhale",glob: "~/.codewhale/sessions/*.json",format: SOURCE_FORMAT_SESSION_JSON.Work items (Moraine fork)
crates/moraine-ingest-core/src/sources/codewhale.rsimplementingIngestSource(
harness()="codewhale",format()=SessionJson), mirroring the Hermes session handlers(
normalize_hermes_session_meta/normalize_hermes_session_messageat hermes.rs:791/891).Handle CodeWhale content-part types
text/thinking/tool_use/tool_result; rolesuser/assistant.sources/mod.rs:pub(crate) mod codewhale;+.register(&codewhale::CODEWHALE)in
registry(), and add"codewhale"tomoraine-config::KNOWN_INGEST_HARNESSES(the
registry_matches_config_known_harnessestest enforces these agree).build_session_meta_record/build_session_message_record(dispatch.rs:883/950) to read CodeWhale's nested identity with Hermes-safe fallbacks:
session_id ← session_doc.session_id OR metadata.id;model ← session_doc.model OR metadata.model;session_start ← session_start OR metadata.created_at;last_updated ← last_updated OR metadata.updated_at.Hermes files have no
metadata, so it's unaffected.compose_hermes_modelis a no-op for CodeWhale(no
base_url).tests/hermes_session_fixture.rs, using a redacted realCodeWhale session snapshot.
eric-tramel/moraine(PR) so it ships in a Moraine release; keep thefork in sync.
Work items (CodeWhale side)
moraine-mcpas a recall tool source (stdiomoraine mcpserver) via CodeWhale's MCPconfig so agents gain the recall tools.
memory.rspush/inject (call sitescrates/tui/src/core/engine.rs:801and
:2996viacrate::memory::compose_block; renderprompts.rs:1209; already off by default viaMemoryConfig.memory_enabled=false) in favor of Moraine pull/recall. Update docs/config comments.Validation
moraine upingests~/.codewhale/sessions; MCPlist_sessions/searchreturn CodeWhale sessionswith correct session id / model / timestamps; end-to-end recall in a CodeWhale agent turn.
Known risks / gaps
"shrank → ignore" guard (dispatch.rs:758) doesn't drop data when a new session has fewer messages
than a prior one (different file, so likely fine — confirm).
created_at/updated_at);events need synthetic monotonic ts from session start + message index (like
hermes_event_dt).tool_resultcontent-part exact shape needs confirmation (Anthropic-style{type, tool_use_id, content}) — handle defensively.metadata.cost/metadata.total_tokens— map into Moraine token accounting ifdesired (non-blocking for recall).