MemoraX Code Architecture

September 9, 2026 ยท View on GitHub

This document describes the stable structure, process boundaries, authority model, runtime flows, and code-placement rules of MemoraX Code. It is a map of the current system, not a roadmap or a complete file inventory.

1. Purpose and Sources of Truth

  • Live source, manifests, and executable tests are the authority for current behavior. This document explains their architectural intent.
  • AGENTS.md defines working rules for coding agents, runtime and data invariants, and Git handoff requirements.
  • CONTRIBUTING.md defines development, debugging, verification procedures, and documentation ownership.
  • SECURITY.md defines security and trust-boundary policy.
  • README owns ordinary installation and first use; Configuration owns settings and their semantics; Troubleshooting owns diagnosis and recovery.

Architecture documentation should remain stable across ordinary refactors. Do not copy volatile values such as package versions, ports, Hook ABI numbers, timeouts, retry counts, batch sizes, endpoints, current test counts, or artifact allowlists into this file. Their source or manifest remains authoritative.

2. System Shape and Package Ownership

MemoraX Code integrates Codex, Claude Code, DeepSeek Harness (DSH), OpenCode, CodeBuddy CLI, WorkBuddy, and Trae with one local Backend. The Backend is a capability-oriented modular monolith. The clients retain ownership of models, model-provider credentials, native tools, model-provider traffic, and native transcript, message, or Hook-event creation.

Around the Backend are:

  • six client deployment adapters;
  • one lower-level shared runtime source layer;
  • one npm assembly and installed-CLI layer; and
  • repository automation that builds, validates, stages, and tests artifacts.
flowchart LR
  subgraph Clients["Client-owned runtimes"]
    Codex["Codex"]
    Claude["Claude Code"]
    DSH["DeepSeek Harness"]
    OpenCode["OpenCode"]
    CodeBuddy["CodeBuddy CLI"]
    WorkBuddy["WorkBuddy"]
    Trae["Trae"]
  end

  subgraph Adapters["Client integrations"]
    CodexAdapter["Codex adapter<br/>plugin, Hooks, canonical skill"]
    ClaudeAdapter["Claude adapter<br/>plugin, Hooks, installer"]
    DshAdapter["DSH adapter<br/>Cordis Turn bridge, Profile lifecycle"]
    OpenCodeAdapter["OpenCode adapter<br/>plugin, installer, skill artifact"]
    CodeBuddyAdapter["CodeBuddy adapter<br/>Hooks, transcript bridge, skill"]
    TraeAdapter["Trae adapter<br/>Global Hooks, skill"]
  end

  Common["adapter-common<br/>records, locks, Hook and Repo Memory helpers"]
  subgraph Backend["Backend package"]
    Service["managed Backend HTTP process"]
    MemoryCLI["memorax-cli process"]
  end
  Npm["npm package sources<br/>wrappers and manifest"]
  Build["scripts<br/>build, stage, materialize"]
  Artifact["assembled npm artifact<br/>installed CLI"]
  MemoraX["MemoraX memory API"]
  Local["local runtime state<br/>trace and lifecycle records"]

  Npm --> Build
  Backend -. "compiled runtime source" .-> Build
  Common -. "runtime source" .-> Build
  CodexAdapter -. "artifact source" .-> Build
  ClaudeAdapter -. "artifact source" .-> Build
  DshAdapter -. "artifact source" .-> Build
  OpenCodeAdapter -. "artifact source" .-> Build
  CodeBuddyAdapter -. "artifact source" .-> Build
  TraeAdapter -. "artifact source" .-> Build
  Build -->|"assembles"| Artifact
  Artifact -->|"lifecycle start"| Service
  Artifact -->|"memory command"| MemoryCLI
  Artifact -->|"trial provision when needed"| MemoraX

  Backend -->|"shared source imports"| Common
  CodexAdapter --> Common
  ClaudeAdapter --> Common
  DshAdapter --> Common
  OpenCodeAdapter --> Common
  CodeBuddyAdapter --> Common
  TraeAdapter --> Common

  Codex --> CodexAdapter
  Claude --> ClaudeAdapter
  DSH --> DshAdapter
  OpenCode --> OpenCodeAdapter
  CodeBuddy --> CodeBuddyAdapter
  WorkBuddy --> CodeBuddyAdapter
  Trae --> TraeAdapter
  CodexAdapter -. "versioned local Hook HTTP" .-> Service
  ClaudeAdapter -. "versioned local Hook HTTP" .-> Service
  DshAdapter -. "versioned local plugin HTTP" .-> Service
  OpenCodeAdapter -. "versioned local plugin HTTP" .-> Service
  CodeBuddyAdapter -. "versioned local Hook HTTP" .-> Service
  TraeAdapter -. "versioned local Hook HTTP" .-> Service

  Clients -->|"shared Skill via client shell"| MemoryCLI
  Service -->|"automatic Search/Add"| MemoraX
  MemoryCLI -->|"explicit Search/Add"| MemoraX
  Service --> Local
  MemoryCLI --> Local

The diagram mixes packaging, source dependency, and runtime-call relationships; the arrow labels distinguish them. It is not an import graph.

2.1 Repository components

Adapters deploy native integrations, bridge client events to Backend commands, and present returned context and diagnostics. Backend client runtimes own the native interpretation used by memory workflows. Model execution and provider configuration remain client-owned.

ComponentStable responsibilityMust not own
BackendLocal memory service, native content interpretation, repository scope, local memory helpers, trace, lifecycle, and update scheduling; see capability ownershipModel execution, client model-provider credentials, or native transcript creation
adapter-commonShared connection and private-record primitives, credential storage, locks, Hook transport/generations, and local memory helpersBackend composition, native content interpretation, MemoraX requests, or client plugin policy
Codex adapterCodex plugin, Hooks, workspace observation, and the canonical shared SkillRollout interpretation or Backend writeback orchestration
Claude Code adapterClaude plugin, Hooks, installer, and marketplace sourceTranscript interpretation or Backend memory orchestration
DSH adapterCordis Turn bridge, persisted-interval delivery, Profile and runtime-generation lifecycle, and supervised Repo MemoryBackend event interpretation or DSH provider/session ownership
OpenCode adapterPlugin and thin loader, SDK record delivery, shell-session identity, workspace evidence, and supervised Repo MemoryBackend message interpretation or model-provider configuration
CodeBuddy/WorkBuddy adapterMarketplace plugin, Hooks, native transcript bridge, and supervised Repo MemoryBackend transcript interpretation or model-provider configuration
Trae adapterManaged Global Hooks, versioned runtime and Skill deployment, and Hook observationGlobal Hooks activation, provider settings, or guessed native Sessions
npm packageInstalled wrappers, setup and update reconciliation, trial provisioning, and package replacementBackend lifecycle semantics, uninstall orchestration, or artifact staging
scriptsBuild, staging/materialization, and repository/artifact checksProduct runtime authority
.githubIssue and pull-request contribution templatesProduct runtime behavior

memorax-code-adapter-common is a source layer consumed by the Backend and all six adapters; it is not an independently deployed service. The npm artifact assembles all runtime trees, but package assembly does not make the npm wrapper the owner of their behavior.

2.2 Physical dependency directions

  • The Backend and the Codex, Claude Code, DSH, OpenCode, CodeBuddy, and Trae deployment adapters may import adapter-common. Adapter-common must not import those higher-level components back.
  • Adapter Hook and plugin runtimes do not import Backend implementation. They communicate through versioned, client-qualified local HTTP commands. Shared adapter-common/src/backend-command.mjs sends those commands with JSON and token headers, a request deadline, and optional caller cancellation. Each adapter resolves current connection authority per request and retains native payload construction, response decoding, status handling, and failure policy. The transport returns the original HTTP response; it does not retry commands or start the Backend.
  • Backend lifecycle may load adapter configuration or installers through lifecycle participants. Request-time memory processing must not depend on plugin installation or install-watchdog behavior.
  • The npm layer locates staged entrypoints. scripts owns how source is materialized into that staged layout.
  • The canonical user-facing memorax-code skill lives in the Codex adapter. Packaging materializes the Claude Code, DSH, OpenCode, CodeBuddy, and Trae artifacts from that source; do not maintain independent skill copies.

Client integration is deliberately not physically symmetric. Codex plugin material belongs to the Codex adapter, while current install, activation, and Hook-trust glue lives in Backend clients/codex. The Claude Code installer lives in the Claude adapter. The DSH adapter owns Profile discovery and mutation plus per-user runtime generation materialization. The OpenCode adapter installs an auto-discovered thin loader and shared skill without editing OpenCode provider configuration. The CodeBuddy adapter owns its marketplace plugin and managed global UserPromptSubmit Hook. Native global Hooks load before plugin initialization, allowing the first prompt to use the same transcript-boundary and prompt-digest correlation as later turns. The plugin retains SessionStart and Stop; its old prompt dispatch is ignored to avoid duplicate handling during updates. The global entry honors native plugin disablement before Backend recovery, and lifecycle disable/remove cleans up only its owned Hook. CodeBuddy CLI and WorkBuddy share that implementation but use distinct codebuddy and workbuddy client identities. Setup discovers and selects them independently. Each installation retains its own configuration root, executable, Hook observations, and pending Turns; Backend session, trace, and writeback identities preserve the same separation. Shared native parsing keeps the original session ID for transcript validation. Legacy WorkBuddy selection is recognized from owned installation metadata, and explicit new client choices take precedence. Lifecycle cleanup never treats the other client's directory as stale installation data. Hook recovery preserves the active client selection and each installation's recorded root and command. The Trae adapter merges only marker-owned Global Hooks and materializes the shared Skill without changing provider settings. These implementations are loaded by their Backend lifecycle participants. Preserve the participant contract and each client's actual authority instead of forcing matching directory shapes.

Lifecycle report interpretation is shared in lifecycle/client-reports.ts. Its static client catalog maps lifecycle IDs and display names to existing report keys. The report projection supplies readiness and presentation data to the orchestrator and CLI while preserving the raw client-specific JSON. It does not discover clients, select defaults, read installation state, or perform lifecycle mutations. Lifecycle configuration and orchestration own selection and defaults; native participants own client-specific discovery and mutations, including DSH Profile ordering and locks.

3. Runtime Flows

The system has two related but distinct planes. The control plane installs and manages integrations and processes. The runtime data plane handles memory operations for live client sessions.

3.1 Installation and lifecycle control plane

sequenceDiagram
  participant User
  participant Update as detached automatic updater
  participant NPM as npm and package-transition hooks
  participant Transition as package-transition record
  participant Setup as setup/reconciliation CLI
  participant Completion as setup-completion record
  participant Generation as Hook runtime generation
  participant Lifecycle as Backend lifecycle CLI
  participant Participants as client participants
  participant Service as managed Backend

  Note over NPM,Lifecycle: Package replacement path, also used by the updater below
  opt running managed Backend or retained DSH state
    NPM->>Transition: record replacement intent
    NPM->>Lifecycle: quiesce managed runtime
  end
  NPM->>NPM: install or replace package files
  opt successfully retired transition exists
    NPM->>Lifecycle: restore and verify managed runtime
    NPM->>Transition: consume only after successful status
  end
  opt explicit recovery after failed restoration
    User->>Setup: update --recover
    Setup->>Transition: lock and validate retired record
    Setup->>Lifecycle: restore and verify installed package
    Setup->>Transition: consume only after successful status
  end

  User->>Setup: interactive setup
  Setup->>Generation: stage immutable Hook runtime
  Setup->>Setup: resolve client selection and connection
  opt Codex selected and detected
    Setup->>Lifecycle: install plugin and activate or verify Hook trust
  end
  Setup->>Lifecycle: start selected integrations
  Lifecycle->>Participants: prepare client integrations
  Lifecycle->>Service: start or retain Backend and check readiness
  opt DSH prepared and Backend ready
    Lifecycle->>Participants: activate DSH runtime authority
  end
  opt lifecycle report and Backend both ready
    Lifecycle->>Generation: activate staged Hook runtime
  end
  Lifecycle-->>Setup: lifecycle result
  Setup->>Lifecycle: status and final readiness checks
  Setup->>Completion: commit only after final verification

  loop completed setup while managed Backend remains running
    Service->>Update: dispatch when durable deadline is due
    Update->>Update: lock, recheck cadence, resolve channel target
    opt target version differs
      Update->>NPM: install exact published target
      Note over NPM,Lifecycle: Uses the package replacement path above
    end
    opt updated or setup-completion version is stale
      Update->>Setup: non-interactive update reconciliation
      Note over Setup,Lifecycle: Reuse staging, lifecycle and verification above
    end
    Update->>Update: persist next check or retry deadline
  end

npm lifecycle, foreground setup, and Backend scheduling have separate authority. npm replacement retires a running managed Backend and restores it with retained client intent, consuming the transition record only after status succeeds. Retained DSH state also triggers retirement and restoration, even without a live Backend PID or when that state is disabled. Fresh or stopped installations without retained DSH state remain stopped. npm lifecycle never detects new clients, accepts credentials, or authorizes Hooks.

Explicit memorax-code update --recover reuses package-transition restoration and its lock for the already installed package. The user's recovery request permits an expired retired record; unattended npm restoration retains its freshness limit. Both paths reject incomplete retirement, invalid records, and future timestamps, and consume state only after successful start and status.

Public memorax-code setup owns disclosure, preferences, credential provisioning or entry, client discovery, initial Hook activation, and Backend reconciliation. It requires an interactive terminal and commits the versioned completion record only after final verification. Invalid or unsupported completion and transition records fail closed. No-argument routing and legacy migration follow the setup state rules.

After completed setup, the managed Backend schedules a detached updater from the durable deadline; client startup Hooks only recover an unavailable Backend. The updater serializes checks through its private record and lock, installs an exact target from the installed release channel, and reuses non-interactive setup reconciliation. It preserves explicit client choices and configuration. Codex Hook changes may be trusted silently only when marketplace identity stays the same and the exact incremental Hook selection validates before and after the config write. Failed verification leaves reconciliation incomplete; a replaced Backend resumes scheduling from the same record.

Hook generation staging and activation are separate decisions: failed Backend readiness must not replace the authoritative generation. Cross-process lifecycle decisions use versioned durable records and bounded locks, not only in-memory serialization.

Concurrent shared Hook recovery is serialized per Backend home and rechecks connection authority and health before starting another Backend. Recovery preserves the current managed client set, falling back to configured selection when no valid active marker is available; the triggering client does not narrow the shared integration set.

Control-plane implementations are grouped by ownership:

  • npm package bin and lib own installed wrappers, foreground setup, package transitions, and detached updates.
  • Backend src/entrypoints/backend-cli.ts and src/lifecycle own process commands, lifecycle orchestration, scheduling, and Backend process authority.
  • Adapter-common owns shared records, locks, and Hook generations. Client lifecycle participants invoke native preparation, status, and removal in the owning Backend or adapter modules.

The DSH adapter installs content-addressed runtime generations from immutable staged source into managed Profiles through DSH's native plugin manager. It never installs or updates DSH or deletes user Profiles. The validated DSH entrypoint and version form durable runtime authority and are revalidated during reconciliation. The Backend lifecycle lock precedes the DSH state lock. Start quiesces old authority, prepares artifacts while disabled, and activates them only after Backend readiness; stop, update, and uninstall disable authority before Profile mutation. Disabled or invalid runtime registers no listeners and cannot recover the Backend. Auto-discovered DSH failures degrade setup and unqualified start or status without blocking the Backend or other clients; explicit client selection remains strict. See DSH configuration and recovery for discovery and Profile details.

The OpenCode adapter materializes auto-discovered plugin and Skill assets without changing model or provider settings. Plugin startup begins a best-effort Backend check; the first prompt shares a bounded interaction budget, while accepted-turn idle writeback may await the full check. Expiry skips that turn's automatic memory handling without cancelling recovery. Recovery uses the package-recorded Node runtime and memorax-code start, exact managed homes, and the existing lifecycle lock. It does not replace client selection, directly spawn the Backend, or recover remote or invalid connection authority. Content-free workspace runtime evidence proves plugin execution only; it is not session, transcript, repository-scope, or lifecycle authority. See client discovery, OpenCode paths, and recovery for operational details.

The Trae adapter materializes a content-addressed runtime, merges only marker-owned Hooks, and installs the canonical Skill. User Hooks remain untouched, and an unmanaged Skill at the target path fails closed. Global Hooks activation belongs to Trae and requires the user's one-time action; successful setup alone does not prove activation. Stop removes managed Hooks but preserves the Skill; uninstall also removes the managed Skill. See Trae configuration for paths and activation instructions.

Account-free setup creates or restores versioned trial credentials through adapter-common's secure credential port and calls MemoraX provisioning to complete an unprovisioned record. Existing-account setup and reuse of ready credentials skip that request. The secure record is authoritative for reuse; the API key is also projected into private configuration. Account, project, and device-mark metadata remain only in secure credential storage. A matching anonymous quota reminder may read the mark for account claiming, but it does not replace configured repository-scoped memory identity.

3.2 Hook and retrieval data flow

Automatic Search on turn-start Hooks is disabled by default. The usual Search path is a client deciding through the shared Skill to call memorax-cli, as shown in Manual memory CLI flow. Hooks still provide native identity, scope, local context, and automatic-writeback coordination when automatic retrieval is off.

sequenceDiagram
  participant Client as supported client
  participant Hook as adapter Hook or plugin
  participant Backend as Backend HTTP / MemoryService
  participant Native as client-specific runtime
  participant Shared as HarnessMemoryRuntime
  participant Provider as local MemoraX provider
  participant Trace as local trace / observability

  Client->>Hook: native event and correlation
  Hook->>Backend: versioned client-qualified turn-start
  Backend->>Backend: authorize and validate command
  alt invalid request
    Backend-->>Hook: error response
  else accepted request
    Backend->>Native: dispatch turn-start
    Native->>Shared: native identity, trace input, optional pre-resolved scope
    Shared->>Shared: resolve scope unless pre-resolved
    Shared->>Shared: register metadata only for a correlated Turn
    Shared->>Trace: record turn-start and current-turn state
    opt automatic retrieval enabled and eligible
      Shared->>Provider: retrieve scoped memory via automatic-retrieval
      Provider->>Trace: emit result through observability hook
      Provider-->>Shared: normalized result
    end
    Shared-->>Native: normalized context, worktree, optional notices
    Native-->>Backend: turn-start result
    Backend-->>Hook: JSON response
  end
  Hook-->>Client: client-specific context or fallback behavior

Important distinctions:

  • Hook or plugin event fields normally supply protocol, correlation, and retrieval input rather than automatic-writeback content. OpenCode's separately supplied SDK records are validated as client-native content. Trae is the narrow exception because it exposes no stable raw Session: its validated, correlated UserPromptSubmit prompt and Stop final assistant message are the primary Trae content authority, not a fallback.
  • The native authority map identifies each client's exact writeback source and owning tests.
  • Required client/session/turn identity and repository scope fail closed when incomplete, conflicting, or unprovable.
  • Adapters identify supported default chat directories as projectless; repository/scope.ts resolves them to scopeKind: general and the shared remote identity <base-user-id>@General. Verified Git identity takes precedence. Recognition is client-owned; scope derivation stays shared. General sharing does not merge client/session identity or physical workspace keys. The directory rules apply to Codex, WorkBuddy, and OpenCode; ordinary workspaces retain their existing rules. Codex can recover an unbound session's General root from the matching rollout's first session_meta record when a new Turn resumes in a child directory. The native initial cwd must match the shared Codex default-directory recognizer, and both Hook and registered cwd must remain inside that root without intervening Git authority. Recovery runs within session serialization, never replaces a live binding, and does not depend on retained trace records. A General session that initially has no cwd may acquire its first physical root only when the corresponding client default-directory recognizer validates that root and Git resolution still yields General. This one-time completion preserves the remote namespace and pending QA, including a Turn whose cwd first arrives at Stop; subsequent changes to the bound root remain mismatches.
  • A malformed or incomplete direct .git directory is the sole documented folder-scope fallback. That degraded scope may upgrade in-session only to a verified Git scope with the same Base User ID and canonical workspace root; for a fixed Base User ID, other scope changes beyond the General first-root completion above remain mismatches. A changed Base User ID requires a new binding; existing Turn metadata remains subject to the coordinator's scope validation.
  • Local mode may authorize loopback requests without a configured token. Token authentication is required when configuration or exposure mode demands it.
  • Client-specific runtimes interpret native formats. Client-neutral memory coordination does not parse, mix, or guess those formats.
  • All supported clients delegate their common memory lifecycle to memory/harness-runtime.ts. Turn start resolves repository scope, records Turn metadata and current-turn trace state, performs optional retrieval, claims supported quota notices, and returns normalized context. Completion passes validated native user/assistant content, exact identity, and a scope resolver to the Turn coordinator. Their client runtimes retain native parsing, correlation guards, retries, interruption recovery, and client-specific materialization and Turn-end trace behavior. Codex also retains workspace registry validation, exact current-turn scope recovery, and native Turn-index resolution. It can provide a pre-resolved scope result, including a failure, without the shared runtime resolving it again. A start observation without a Turn ID can resolve scope and record trace, but cannot register a writable Turn, claim quota notices, or retrieve memory. OpenCode retains SDK message lineage and compaction-continuation validation, interrupted-Turn handling, and the requirement for a prior session scope binding at completion. Its start trace keeps the opencode-plugin source; Turn-start diagnostics use the common metadata-registration stage before trace writes. Trae publishes its active Turn snapshot through the synchronous onTurnRegistered callback, immediately after coordinator registration and before trace or retrieval can yield to a concurrent Stop. Its per-session start queue, interruption records, and active-state cleanup remain client-owned. DSH supplies a start-trace request containing only start_seq, keeps the dsh-cordis source, and adds the native start sequence to retrieval deduplication without changing Turn identity. It disables both pending and retrieval quota-notice claims. Persisted event-interval validation, interruption handling, and restart scope recovery remain DSH-owned.
  • OpenCode's awaited chat.message plugin event supplies the correlated user prompt and injects accepted retrieval plus shared Skill reminder, User Profile, and Procedure Memory context into that message's system context. Claimed Search and Add quota notices are dispatched through best-effort TUI toasts without entering model context or blocking the prompt path. Its stable session.compacted event marks a durable supplemental reminder for the next real user message; synthetic and compaction messages do not consume that pending state. Local reminder evaluation remains independent of Backend recovery. Its shell.env event binds the native session identity and makes the packaged memory CLI available to agent-run shell commands.
  • Trae UserPromptSubmit creates a Turn ID from the native session ID, local timestamp, and normalized prompt digest. The adapter persists one accepted active-turn record per Session and pairs Stop with that record. Backend start handling marks a replaced Turn interrupted. The writeback and restart limits are described below; this integration has no pending completion queue and does not reconstruct content from unrelated local files.

3.3 Manual memory CLI flow

The shared memorax-code Skill routes coding tasks to the relevant memory instructions. When the task calls for persistent recall, the client runs memorax-cli search through its shell tool and uses the returned scoped memory. Users can also invoke the same CLI directly. This explicit Search path is independent of the automatic-retrieval setting.

flowchart LR
  Task["coding task"] --> Skill["shared Skill<br/>decide whether to search"]
  Skill --> CLI["memorax-cli search"]
  CLI -->|"resolve"| Scope["repository scope resolver"]
  Scope -->|"config and authorized scope, or failure"| CLI
  CLI -->|"scoped query only after resolution succeeds"| Provider["local MemoraX provider"]
  Provider --> Remote["MemoraX Search API"]
  Remote --> Provider
  Provider -->|"normalized result"| CLI
  CLI --> Result["scoped result or error to client"]
  CLI -. "when trace binding is available" .-> Trace["local trace"]

memorax-cli enters through Backend src/memorax-cli.ts and src/memory/cli.ts. It does not traverse Hook HTTP or the MemoryService composition, but it reuses the repository-scope, MemoraX-provider, and local-trace components. Manual Add additionally validates user-supplied --reason metadata. The direct entrypoint is not permission to fall back to unscoped provider calls or to reconstruct identity from unrelated process state.

In an integrated client, the CLI validates the exact current-Turn context to reuse its workspace kind, including projectless, so explicit Add/Search and automatic writeback resolve the same General scope. WorkBuddy/CodeBuddy tools can supply native CODEBUDDY_SESSION_ID when the SessionStart environment-file bridge is unavailable. Without that context, standalone commands resolve their working directory. General changes the remote namespace for subsequent operations; it neither migrates old memory nor searches both the old and new namespaces. Even when the current Turn has a projectless hint without cwd, the CLI validates its command directory before using General. Git scope conflicts and unreadable paths reject the operation before any provider request.

After a degraded direct .git directory is repaired, each CLI operation resolves the verified Git scope immediately; no client-session restart is required.

3.4 Automatic writeback

Writeback is a separate branch, not the tail of every memory operation.

flowchart TD
  Completion["Codex, Claude Code, or WorkBuddy<br/>completion signal and correlation"] --> Hook
  SDK["OpenCode SDK messages"] --> Hook
  DSH["DSH persisted Session header<br/>and exact event interval"] --> Hook
  Trae["Trae Stop and persisted active-turn record"] --> Hook
  Hook["adapter: construct client-qualified writeback command"] --> HTTP

  HTTP["Backend HTTP: authorize and validate schema"] -->|"valid"| Native
  HTTP -->|"invalid"| Error["HTTP error response"]
  Files["Codex rollout / Claude or WorkBuddy transcript"] --> Native
  Native["client runtime: materialize content<br/>and validate native correlation"] -->|"eligible content"| Shared
  Native -->|"rejected or interrupted"| Result

  Shared["HarnessMemoryRuntime and turn coordinator:<br/>validate metadata and current scope"] -->|"valid"| Runtime
  Shared -->|"rejected"| Result
  Runtime["automatic writeback:<br/>settings, bounds, redaction and deduplication"] -->|"rejected"| Result
  Runtime -->|"accepted"| Result
  Result["HTTP result: scheduled or skipped"]

  Runtime -->|"new accepted content"| Pending
  Pending["immediate dispatch or buffered flush,<br/>then chunking"] -->|"eligible for dispatch"| Provider
  Pending -->|"pending fallback scope upgraded"| Discard["discard pending fallback content"]
  Provider["local MemoraX provider:<br/>Add request and normalized result"] --> Remote
  Remote["MemoraX Add API"] -->|"initial response"| Provider
  Provider -->|"operational event through injected hook"| Trace["local observability / trace"]

The graph shows routing rather than a fixed response/dispatch order. Rejected content stops locally; accepted duplicates need not issue another Add request.

  • For completed content, local enqueue acceptance is the metadata-consumption point. Interrupted Turns can instead discard metadata with an explicit reason. Unbuffered dispatch starts during enqueue. Buffering defers dispatch until a flush; turn or size limits can trigger that flush during enqueue.
  • Buffering and chunking belong to the memory capability; rollout, transcript, DSH event-interval, and SDK message parsing remains client-specific.
  • Native materializers pass the selected QA timestamps through the shared completion contract. The coordinator supplies explicitly labelled observations when native times are absent; automatic enqueue freezes any remaining fallback before buffering. Message timestamps and source labels survive redaction, chunking, and retries. Provider Add metadata carries only the aligned time-source labels, not local trace context. See timestamp semantics.
  • DSH accepts only a contiguous native interval bounded by the matching turn/start and completed turn/end. The Backend materializes direct user text and visible model-assistant text; plugin recall, tools, reasoning, and incomplete Turns are excluded. Only non-delegated sessions are eligible.
  • A valid persisted DSH interval can restore automatic writeback after a Backend restart without cached Turn metadata; repository scope is still resolved and validated from the persisted Session workspace.
  • DSH uses the shared retrieval, buffering, chunking, redaction, provider, and client-qualified trace paths. Its normalized Search and Add operations enter DSH trace without copying the native Session Event Log.
  • OpenCode terminal handling accepts only matching SDK user and completed assistant records for the correlated session and native parent lineage. When OpenCode compacts an active Turn, the lineage must prove the compaction tail_start_id, its marked synthetic continuation, and the final assistant; only the original user text and visible final reply are materialized. A completed native assistant error closes the Turn as interrupted without writeback; malformed errors, summary, compaction, incomplete, or identity-mismatched messages are rejected. It does not fall back to plugin prompt text or local database guesses.
  • Because OpenCode terminal notifications are event callbacks, the plugin serializes idle- and interruption-triggered SDK reads per session, tracks the resulting work, and drains already-started tasks during plugin disposal.
  • Trae validates the prompt digest bound into the command's Turn ID and uses the paired Stop assistant text. The Backend rejects commands naming a replaced Turn while its active/interruption state remains available. A complete validated Hook command can restore writeback after Backend restart. The validated Turn ID retains the prompt observation time; optional assistantObservedAt preserves the Stop Hook observation across HTTP delivery. The adapter pairs native Stop with its persisted active record; it does not independently validate a native Stop Turn ID. An old Stop arriving after that record is replaced therefore is not guaranteed to be rejected. Missing or invalid Hook-pair content is not reconstructed from raw Session files.
  • When a degraded direct-.git scope upgrades to verified Git scope, the buffer runtime cancels and discards pending fallback turns for the same client and session before buffering under the Git scope. It does not migrate or flush those turns across namespaces.
  • The Backend records the initial Add response but does not poll asynchronous Add task status after that response.

3.5 Repo Memory coordination

Repo Memory is repository-local guidance under .repo_memory, not a MemoraX provider response. In all supported clients, an accepted turn-start result exposes a worktree to the adapter integration only for a verified Git scope. Codex, Claude Code, and CodeBuddy/WorkBuddy Hooks, DSH's native pre-step integration, and OpenCode's awaited chat.message handler may schedule a missing bundle build using adapter-common supervision, locking, and job-policy helpers. They must use the Backend-resolved worktree rather than adapter-local workspace input. Trae consumes existing Repo Memory context and exposes the shared Skill, but does not schedule background work because no supported headless Trae worker exists.

The Backend owns the TypeScript Repo Memory collector, delta detector, provider facets, and validator under src/repo-memory, exposed through memorax-code repo-memory. The canonical Skill ships a thin scripts/repo-memory.mjs launcher that uses the staged Backend runtime in the npm package or the installed memorax-code command after the Skill is copied into a client-specific directory. Repo Memory therefore shares the required Node.js runtime with the rest of the package.

User Profile management lives separately under Backend src/personal-memory. The canonical Skill's scripts/user-profile-memory.mjs launcher runs the compiled local helper directly or locates it through the installed memorax-code user-profile command. Listing, adding, updating, and deleting preferences do not require a running Backend service or a network request. The helper preserves the existing .repo_memory/user-profile/preferences.md format and performs mutations under a cross-process lock with atomic file replacement. Its lock is separate from the legacy profile writer's lock; concurrent writes by legacy and current writers are not coordinated. Existing preferences continue to be read and injected by adapter-common. Procedure Memory remains managed as topic Markdown files through the shared Skill.

Codex and OpenCode keep the generic shared Skill reminder available when the Backend or repository scope is unavailable. Trae evaluates reminders only after an accepted turn-start response and active-record commit; a response without repository scope still permits its generic reminder. Codex, DSH, OpenCode, CodeBuddy/WorkBuddy, and Trae enable User Profile and Procedure Memory builders only with a Backend-resolved worktree. Their original client workspace is trace metadata, not local-content authority. Claude Code's independent reminder Hook instead resolves the Git root from Hook cwd, falling back to its local workspace registry when cwd is absent, without waiting for a Backend worktree result.

A relevant repo-read can invoke supervised maintenance in the five headless-capable client integrations. The runner validates the bundle and selects a background build, update, or no-op according to policy. DSH maintenance runs through an enabled, managed headless-capable Profile. For OpenCode, both on-demand maintenance and first-eligible-prompt initialization run through a short-lived subagent session. The detached worker reuses the active OpenCode server when it is reachable. When no server URL is available or initial session creation fails at the transport layer, a worker with a configured OpenCode command can start an authenticated, loopback-only opencode serve process with an in-memory database and close it afterward. HTTP/session-response failures and later prompt failures do not select this fallback. Desktop-only installations with a reachable server do not require a standalone OpenCode CLI. Trae remains outside this supervised path until it exposes a suitable headless execution authority.

4. Backend Modular Monolith

The Backend is organized by capability, with lightweight capability-local layering. Its top-level directories are not a strict linear dependency chain.

4.1 Composition roots and stable facades

LocationArchitectural roleMust remain free of
src/entrypoints/backend-cli.tsProcess and management-CLI composition; dispatches lifecycle, client integration, and raw server commandsMemory business rules
src/app/backend-server.tsRuntime HTTP composition root; creates routes, memory service, observability, and shutdown resourcesInstallation and plugin lifecycle
src/memory/service.tsSecondary composition point inside the memory capability; assembles client runtimes, turn coordination, repository sessions, and automatic memory workflowsNode HTTP and process entrypoint concerns
src/server.tsStable executable/import facade for the Backend serverApplication composition logic beyond delegating to owning modules

4.2 Source layout

Capability directories hold implementation; their responsibilities are defined in the ownership table. Each supported client has one directory under clients/.

src/
  app/
  clients/<client>/
  config/
  entrypoints/
  lifecycle/
    backend/
  memory/
  personal-memory/
  provider/
    memorax/
  repo-memory/
  repository/
  shared/
  trace/
  transport/
    http/

The source root also contains a small, tested set of stable compiled entrypoints and compatibility facades. It is not another implementation area.

4.3 Capability ownership

PathResponsibilityImportant boundary
src/entrypointsDirect-execution detection, CLI parsing, command dispatch, process signals, and process-facing orchestrationDoes not own memory rules
src/appBackend state/security, runtime resource assembly, observability fan-out, active requests, and graceful shutdownDoes not install plugins or own the lifecycle control plane
src/transport/httpShared Backend HTTP authorization, request/JSON helpers, error mapping, health, and Hook wire adaptationOutbound provider HTTP remains with the provider capability
src/lifecycleContracts, participants, client selection, locks, service orchestration, install watchdog, and client integration removalRequest-time memory flow does not depend on it
src/lifecycle/client-reports.tsStatic lifecycle client identity and pure projections of adapter readiness and diagnostic summariesNo native discovery, filesystem or process access, lifecycle mutations, or replacement of raw client reports
src/lifecycle/backendManaged process, PID/token/connection records, status probing, cleanup, and shutdown requestsHelper contracts do not depend back on the full service implementation
src/clients/<client>Native interpretation, correlation, interruption/recovery, trace adaptation, and lifecycle participation; delegates common memory workflows to the shared harness runtimeRequest runtime stays HTTP-composition independent and uses only the matching native authority; native deployment follows package ownership
src/memoryMemory commands, retrieval, writeback, turn coordination, repository session pinning, manual CLI, and buffering/chunkingClient-neutral modules do not parse native transcript formats
src/memory/harness-runtime.tsCommon Turn-start and materialized-completion workflows for all supported clients; publishes registered Turn state synchronously and owns locally created memory resources while reusing injected shared resourcesNo client implementation, HTTP, app/lifecycle, or direct provider-transport imports; diagnostics enter through a port and native interpretation stays with each client
src/personal-memoryLocal User Profile listing, normalization, duplicate detection, updates, deletion, and atomic storageNo Backend service, provider calls, transcript processing, or Procedure Memory mutation
src/repo-memoryRepo Memory preparation, local and provider facet collection, delta detection, and bundle validationPrepares bundle directories and the repository ignore entry, collects raw evidence, and validates output; agents author durable Markdown memory
src/repositoryRead-only repository identityScope derivation does not execute Git or use synchronous filesystem reads
src/provider/memoraxMemoraX config interpretation, Search/Add payloads, HTTP transport, and normalized resultsIndependent from server routing and plugin lifecycle
src/traceClient-qualified trace config/context/store, current-turn state, retention, and JSONL persistenceTrace core has no outbound-network authority
src/configBackend, MemoraX Code, and proxy environment/config interpretationConfiguration parsing stays independent of route composition
src/sharedNarrow utilities such as JSONL append, record guards, debug logging, and Windows invocationNot a dumping ground for business types or policy

4.4 Stable Backend root surfaces

Root moduleRole
memorax-code.tsManagement CLI process entrypoint
memorax-cli.tsManual memory CLI process entrypoint
repo-memory.tsLocal Repo Memory helper process entrypoint
user-profile.tsLocal User Profile helper process entrypoint
service-entrypoint.tsGuarded managed-child-process entrypoint
server.tsmemorax-code-backend executable and stable createBackendServer export facade
codex-adapter-lifecycle.tsCompatibility re-export of the Codex lifecycle participant
jsonl-append.tsCompatibility re-export of the shared JSONL primitive
windows-cli-invocation.tsCompatibility re-export of the shared Windows invocation primitive

The exact root allowlist is enforced by the Backend source boundary test. New implementation must go into a capability directory. Adding a root module is a deliberate compatibility or packaging decision and requires the architecture contract to change in the same patch.

5. Dependency Model and Executable Contracts

5.1 Why there is no top-level layer order

Some top-level directories have imports in both directions while the module graph remains acyclic:

Directory relationshipWhy it exists
app and transportThe app composes routes; shared HTTP helpers consume the narrow BackendState contract
clients and memoryMemory service composes client runtimes; client runtimes consume client-neutral memory contracts
clients and lifecycleClients implement lifecycle participants; orchestration consumes those participants
clients and traceClient runtimes record trace; trace Store/model code consumes client activity, token, and identity types
memory and providerMemory invokes the provider; provider emits memory-owned observability contracts
memory and traceMemory carries trace context; trace context uses the memory project identity

These are directory-level relationships, not source-module cycles. Do not draw a fictional global entrypoint -> application -> domain -> infrastructure rule over this repository. Move composition outward, define narrow ports in the capability that owns their meaning, and keep the complete module graph acyclic.

Other dependencies are one-way: lifecycle process helpers consume app state/security primitives, and memory workflows consume repository-scope resolution. HTTP composition does not import lifecycle, and repository-scope resolution does not import memory workflows.

5.2 Important ports and contracts

ContractOwned byPurpose
MemoryServicememory/service.tsHTTP-independent command surface for memory operations
HarnessMemoryRuntimememory/harness-runtime.tsCoordinates common Turn-start and validated completion workflows; preserves ownership of injected repository sessions, Turn coordination, writeback, and quota-notice resources
MemoryObservabilityHookmemory/observability.tsEmits normalized operational events without importing the concrete trace Store or Backend logging
MemoryDiagnosticLoggermemory/observability.tsInjects diagnostics without binding memory kernels to Backend debug output
MemoryTurnCoordinatormemory/turn-coordinator.tsCorrelates and validates client-neutral Turns and controls metadata consumption
RepositoryMemorySessionRuntimememory/repository-session.tsPins and validates repository scope, including the bounded degraded-direct-.git to verified-Git upgrade
AdapterLifecycleParticipantlifecycle/participant.tsLets lifecycle orchestration use client adapters without embedding their implementation details
Lifecycle client reportslifecycle/client-reports.tsMaps existing client report keys to common readiness and presentation data without changing native report authority
Backend lifecycle contractslifecycle/contracts.tsSeparate BackendServiceOptions, injectable runtime, resolved endpoint, and BackendServiceResult from managed-service implementation

Ports stay with the capability that owns their semantics. A contract used by multiple directories does not automatically belong in shared.

5.3 Executable architecture contracts

ContractLocationEnforcesInspect or update when
Backend source boundariespackages/ts/memorax-code-backend/test/architecture/source-boundaries.test.mjsRoot facade allowlist, discovered client-runtime coverage, selected direct forbidden imports including shared harness and lifecycle-report neutrality, lifecycle delegation, and an acyclic relative-import graphAdding a client or root surface, crossing capability boundaries, or changing a composition root
Local-only trace boundaryscripts/check-local-trace-only.mjs and its testsReviewed network-capable production modules, trace-core isolation, unreviewed trace-aware outbound bridges, and staged artifact/symlink containmentMoving or adding network code, trace-aware outbound code, or staged paths
Package shapenpm package tests and package-build/check scriptsExecutable wrappers, staged runtime layout, canonical source mapping, compatibility paths, and artifact allowlistsChanging entrypoints, packaging sources, materialization, or layout
Harness integration coveragepackages/npm/memorax-code/test/harness-coverage.test.mjsDiscovered adapter packages match Backend client directories; runtime trees and the canonical Skill have npm source mappings; make test reaches every adapter suite and the independent common and shared Skill suitesAdding a harness, changing adapter directory layout, source mapping, or test recipes
Documentation contractscripts/check-docs.mjs and its testsRelative file targets in registered documentation, personal absolute paths, and shipped-document consistencyAdding a root document or changing document/package layout
Platform-specific consumersRepository scripts and platform harnessesExplicit test paths, test-name patterns, and platform lifecycle scenariosMoving, splitting, or renaming tests or platform entrypoints

The forbidden-import rules are targeted direct-import checks for named modules; they are not a universal directory-level or transitive dependency checker. The cycle check covers recognized literal relative import/export edges among TypeScript modules within Backend src, including type-only imports. It does not traverse adjacent packages or computed import specifiers. The local-only gate detects known network expressions and trace-storage imports in its registered source roots; it is not a complete data-flow analysis. The documentation gate checks file targets, not heading fragments.

Client runtime rules discover modules that import memory/harness-runtime and require every native client source directory to have a covered runtime. New runtimes therefore join the shared checks without depending on a fixed filename or a duplicated client list. Native-reader rules remain explicit; add newly introduced readers to the applicable rules and their client-owned behavior tests. Lifecycle report projections are separately checked against native-client, filesystem, process, HTTP, and lifecycle-implementation imports.

Harness integration checks discover packages/ts/memorax-code-<client>-adapter directories and require lowercase kebab-case client IDs rather than maintaining another client catalog. They check the existing Makefile recipe structure and source mappings, not installed-client behavior. The same gate requires the independent common and shared Skill targets to discover their tests recursively and remain reachable from make test. Adapter src, hooks, runtime-hooks, and scripts directories must be declared for staging. The local-only trace gate recognizes those runtime directories and shared Skill scripts for every adapter, including staged copies. Shared Skill copies map to the canonical Codex source for reviewed-network checks; discovering a new adapter does not approve its network-capable modules. New directory conventions still require explicit updates to these checks and their native or installed-package tests.

Do not weaken an executable boundary merely to make a new import or path pass. If the intended architecture has not changed, move composition outward or introduce a narrow port. If the boundary itself intentionally changes, update this document and the executable contract together.

6. Authority and Trace Boundaries

The normative fail-closed, privacy, and publication rules remain in the AGENTS guidance for Hook, session, and scope invariants and data and user-facing boundaries.

6.1 Authority map

ConcernAuthorityDerived or non-authoritative views
Models, model-provider credentials, native tools, and model-provider trafficThe native clientBackend and adapters must not proxy or persist this authority
Hook command identityVersioned, client-qualified command plus validated required session/turn fieldsParsed HTTP request objects
Automatic writeback contentThe matching client and Turn's native authorityHook or plugin text is not a fallback outside Trae's primary authority; trace, latest-Turn guesses, local database guesses, and another client's format are never fallbacks
Workspace and repository identityRead-only scope resolution; for a fixed Base User ID, the live session binding permits only a same-root degraded-direct-.git to verified-Git upgradeProject labels and Hook cwd
Backend connection and managed-process ownershipVersioned private connection/token/PID records plus lifecycle lock/version validationIn-memory state in any one process
Package replacement intentVersioned private package-transition record plus its bounded locknpm process state or the presence of installed package files
Completed foreground setupVersioned private setup-completion record written after final verificationConfiguration-file presence, Backend liveness, or detected clients
Automatic update cadenceVersioned private automatic-update record plus its bounded lockManaged Backend timer state or client process lifetime
Quota remindersVersioned private local runtime record keyed by a one-way connection fingerprint for deduplication; normalized MemoraX balances for the quota amount; a ready secure trial record matching the active API key for optional anonymous Mark ID textAccount registration status, raw API keys, and in-memory reminder state are not quota-reminder authority
MemoraX memory results and Add acceptanceNormalized response from provider/memoraxObservability and trace
Persisted current-turn operational stateClient-qualified current-turn records with Session and Turn checksCLI workspace association and exact recovery; native content is independently validated
Trace historyClient-qualified local trace eventsDiagnostics; not native content or general Turn-identity authority
Repo Memory bundleRepository-local .repo_memory files authored through explicit Skill operations or supervised jobsBackend readiness and client-injected guidance

Native writeback authority

This map is the detailed source for per-client content authority and its owning suites. The automatic writeback flow describes completion, interruption, and recovery behavior. Test links identify contract coverage, not real-client E2E results.

HarnessAutomatic writeback authorityNative Backend testsAdapter tests
CodexExact Turn in rollout JSONLCodexCodex adapter
Claude CodeCorrelated prompt in transcript JSONLClaudeClaude adapter
DSHExact persisted Session Event Log intervalDSHDSH adapter
OpenCodeMatching SDK session-message recordsOpenCodeOpenCode adapter
CodeBuddy/WorkBuddyCorrelated native transcript JSONLCodeBuddyCodeBuddy adapter
TraeValidated Turn-ID and correlated UserPromptSubmit/Stop Hook pairTraeTrae adapter

6.2 State classes and shutdown ownership

Ephemeral process state includes active HTTP requests, turn coordination, repository-session bindings, in-flight provider operations, and observability writes.

Durable local state includes configuration, private runtime, setup-completion, package-transition, automatic-update, and trial credential records, active client selection, client-qualified trace JSONL, reminder cadence and quota-reminder state, and Repo Memory. State shared across processes requires a bounded lock, atomic replacement, or version validation appropriate to its record. An in-memory mutex is not cross-process authority.

Shared JSON file locks publish a complete owner record through an exclusive same-directory hard link. An unfinished owner record is never visible at the public lock path. Private publication and stale-reaper claims share the versioned, process-qualified claim namespace so abandoned claims remain recoverable. Lock storage must support hard links; unsupported storage fails closed rather than falling back to an incomplete or unlocked publication. CodeBuddy Hook pending state uses this shared lock and private atomic record publication. Its legacy directory lock retains the same path and blocks new acquisition until released; an unprovable abandoned directory is not removed based on age. Pending schema, correlation, and pruning remain client-owned.

Backend-owned remote memory state is limited to MemoraX memories and Add tasks. The provider adapter is the network boundary for documented memory payloads; the Backend does not poll an Add task after its initial response.

The runtime composition root owns bounded graceful shutdown. It closes HTTP intake, waits for active requests, and then drains the memory service and observability within one deadline. It waits for already-started background work before closing the memory service. Lifecycle control requests shutdown rather than reaching into those resources and closing them ad hoc.

6.3 Observability and local-only data flow

flowchart LR
  Events["Backend service<br/>retrieval and writeback events"]
  Fanout["app/memory-observability"]
  LocalWriters["turn, reminder, and CLI trace writers"]
  Trace["client-qualified local trace"]

  Events --> Fanout
  Fanout --> Trace
  LocalWriters --> Trace

Retrieval, writeback, and provider kernels emit operational events through injected observability and diagnostic ports. The Backend composition root selects their local sinks. Turn registration in the shared harness runtime, reminder recording, and the manual CLI also use the trace Store directly for their local records; CLI composition supplies its own observability hook. These paths are not all mediated by app/memory-observability. Memory-service kernels receive Backend diagnostics through a port; CLI composition can use the Backend debug logger directly.

Current-turn records share the trace Store and existing paths but serve an operational role. Their read, write, and outcome updates are independent of trace.enabled, so disabling event capture does not change CLI workspace scope or remove exact recovery context. They retain only identity, path, and lifecycle metadata; Session checks, freshness checks, and session retention still apply. The observability sink checks the effective trace configuration for each event rather than freezing the enabled clients at Backend startup.

Raw native transcript files, transcript paths, and retained trace files stay local. Only normalized Search and Add requests cross the MemoraX provider boundary. An Add request may carry messages materialized from the exact native Turn, but it does not upload the raw file or unrelated transcript content. A production module that gains network capability must be explicitly reviewed by the local-only gate; trace-core modules must remain network-free, and a module must not combine trace storage with outbound authority without a reviewed contract.

For DSH, Cordis turn/start establishes only live trace identity. After turn/end, the adapter flushes persistence and supplies the exact native Turn interval; only a Backend-validated interval may produce normalized turn_materialized content and writeback trace events. The raw Session Event Log and its path are never copied into trace.

7. Packaging and Distribution

flowchart TD
  BackendSource["Backend TypeScript source"]
  BackendBuild["Backend dist"]
  NpmSource["npm wrappers and manifest"]
  CommonSource["adapter-common runtime source"]
  AdapterSource["client adapters<br/>canonical Skill and plugin sources"]
  Stage["npm staging tree"]
  Materialize["skill and marketplace materialization"]
  Gates["staged layout, source, and local-only checks"]
  Pack["npm pack"]
  PackedGates["packed file list and extracted-artifact checks"]
  InstallTest["isolated installed-package validation"]

  BackendSource --> BackendBuild
  BackendBuild --> Stage
  NpmSource --> Stage
  CommonSource --> Stage
  AdapterSource --> Stage
  Stage --> Materialize
  Materialize --> Gates
  Gates --> Pack
  Pack --> PackedGates
  PackedGates --> InstallTest

Source prechecks run before staging. Staging and materialization are logical phases of the same build; packed-file and extracted-tarball checks run after npm pack and before installation tests.

  • Backend TypeScript is compiled before staging; generated dist is not committed.
  • Adapter-common and adapter .mjs runtime trees are staged from declared, tracked source.
  • All client Skill artifacts share the canonical Codex source. The Claude marketplace is also materialized from its canonical source; packaging may rewrite contained relative imports for the staged topology. Source mappings are declared in npm-source-files.mjs.
  • Client lifecycle installs managed artifacts from the staged package, as described in the control plane. DSH additionally materializes per-user runtime generations from read-only staged source; its Profile artifact excludes lifecycle control-plane code.
  • Installed wrappers use run-entrypoint.mjs to locate staged Backend and adapter entrypoints.
  • Artifact gates reject undeclared paths, unsafe symlinks, cache/build debris, and local-only data-boundary violations.
  • Build, extracted-tarball, and installed-package checks share the required artifact contract in scripts/npm-package-layout.mjs: declared public commands, plugin manifests, shared Skill launchers, and key process entrypoints. Source mappings cover internal files; the publish allowlist remains a separate restriction on permitted paths.
  • Run installed-package checks in the isolated development environment. Inherited client-home, alias, and command overrides must not select developer state; the package script does not clear every override itself.

Root architecture and contributor guidance are repository documents, while shipped-docs.json remains the authority for the docs/ pages included in the npm package.

8. Test Architecture and Change Routing

Backend tests generally mirror capability ownership. They do not mirror every source file and are not divided first into unit and integration layers. Repo Memory is a cross-package exception: its collection, validation, and update tests live in the repository-root test/shared-skill suite and exercise the compiled Backend helper through the canonical Skill launcher. Backend-relative paths are used below unless a different package or the repository root is named.

Backend source responsibilityPrimary test area
src/apptest/app
src/clients/<client>test/clients/<client>
src/configtest/config, with composition coverage in test/app and MemoraX configuration coverage in test/provider/memorax
src/entrypoints and root executable behaviortest/entrypoints; management-CLI lifecycle behavior in test/lifecycle; root allowlist in test/architecture
src/lifecycle and src/lifecycle/backendtest/lifecycle and test/lifecycle/backend
src/memorytest/memory
src/repo-memoryRepository-root test/shared-skill/repo-memory-builder*.test.mjs and repo-memory-updater.test.mjs through the canonical Skill launcher
src/personal-memorytest/personal-memory; canonical Skill launcher integration in repository-root test/shared-skill
src/provider/memoraxtest/provider/memorax
src/repositorytest/repository
src/sharedtest/shared
src/tracetest/trace
src/transport/httptest/transport/http

Placement rules:

  • Cross-capability server composition belongs in test/app; wire-level Hook protocol behavior belongs in test/transport/http.
  • Area-specific fixtures belong in test/<area>/support; only helpers truly shared across responsibilities belong in test/support.
  • test/architecture has no source counterpart. It owns source topology, root-surface, delegation, and dependency-cycle contracts. HTTP route behavior belongs in test/transport/http and test/app.
  • Backend behavior tests build and exercise dist; architecture tests inspect src directly.
  • Direct common contracts belong in packages/ts/memorax-code-adapter-common/test. Canonical Skill guidance, resources, and cross-package launcher integration belong in repository-root test/shared-skill, even though the canonical Skill source remains in the Codex adapter package. Native Hook wiring and consumer integration stay in the corresponding adapter suites.
  • In mixed adapter test files, separate direct common API checks from native integration. Backend recovery options, job marker/lock records, and profile readers have direct common tests. Repo Memory supervisor and evaluator tests also call common APIs directly, using real Git repositories and isolated worker processes. Generic runner and validator fixtures exercise the job protocol without depending on an adapter, Backend build, or Skill launcher. These fixtures do not validate the real Repo Memory artifact schema; that remains covered through the canonical Skill in test/shared-skill and native launcher integration. Adapter suites retain command and metadata resolution, final-message delivery, canonical-validator wiring, Hook context injection, and Backend-authorized worktree selection.
  • Backend, adapter-common, and shared Skill suites discover nested tests recursively. The six adapter suites currently discover only flat test/*.test.mjs; their package scripts must change before tests are nested.
  • Adapter-common and shared Skill suites have independent Make targets without separate package manifests. Common changes also require affected consumer coverage: Backend, shared Skill, all six adapters, and package checks when staged runtime layout is involved.
  • Before moving, splitting, or renaming tests, search scripts and .github for explicit paths and test-name patterns.

Contributor-facing verification profiles are centralized in CONTRIBUTING.md, including the Backend build prerequisite for standalone shared Skill, Codex, and CodeBuddy/WorkBuddy tests. Change routing uses those named profiles rather than copying commands here. The harness onboarding checklist connects native authority, lifecycle reporting, packaging, and existing test contracts without introducing a separate adapter test framework.

Change surfacePrimary evidenceContracts to inspectVerification profile
One Backend capabilityMatching test/<area>Source boundaries when imports changeBackend
Repo Memory collection, validation, or updateShared Skill tests against the compiled Backend helper through the canonical launcherSource boundaries and canonical Skill launcherRepo Memory
Repo Memory scheduling, supervision, or update policyDirect common supervisor/evaluator tests and affected native launcher integrationWorker protocol and canonical Skill launcherAdapter-common/shared Hook + Repo Memory
Shared Skill guidance, resources, or launchersRepository-root test/shared-skillCanonical source mapping and package shape when stagedShared Skill; add Install/artifacts when staged runtime or package layout changes
Runtime compositiontest/appBackend source boundariesBackend
Hook HTTP or adapter-visible command schematest/transport/http and affected adapter suitesBackend source boundaries and package shape when stagedBackend + Adapter-common/shared Hook; add Install/artifacts when staged package shape changes
Backend root entrypoint or compatibility facadeEntrypoint, architecture, and npm package testsSource boundaries and package shapeBackend + Install/artifacts
Client-native parsing or identitytest/clients/<client>Source boundariesBackend
Client adapter plugin or Hook deploymentMatching adapter suite and affected Backend contract testsPackage shape when stagedCodex, Claude Code, DSH, OpenCode, CodeBuddy/WorkBuddy, or Trae; add Adapter-common/shared Hook for shared Hook source and Install/artifacts for staged package shape
Adapter-commonDirect common contracts and affected Backend, shared Skill, and adapter testsPackage shape when staged layout changesAdapter-common/shared Hook; add Install/artifacts when staged runtime or package layout changes
MemoraX provider, trace, or outbound transportMatching Backend testsLocal-only trace boundaryBackend + Trace/local-only boundary
Test relocationMoved owning suitePlatform-specific consumersMatching named profile
Packaging/materializationnpm package tests and artifact gatesPackage shape and local-only trace boundaryInstall/artifacts
Cross-package architectureAll affected suitesEvery affected executable contractBroad cross-layer; add Install/artifacts when staging or layout changes
Documentation onlyDocumentation contractLinks and root/shipped-doc registrationDocumentation

9. Maintaining This Document

Update ARCHITECTURE.md in the same change when any of these move or change meaningfully:

  • package ownership or a physical package dependency;
  • a composition root or process boundary;
  • capability directory responsibility;
  • a stable root entrypoint or compatibility facade;
  • state, transcript, repository-scope, memory, or trace authority;
  • an intentional forbidden-dependency exception;
  • the local-only data or packaging boundary; or
  • test ownership and executable architecture contracts.

An implementation refactor within an existing documented capability does not require an architecture update when ownership, authority, dependencies, entrypoints, and test placement remain unchanged.

Do not record current file counts, line counts, commit IDs, pull requests, temporary branches, or future split candidates here. Those are historical or planning data, not architecture.

Related documents: