ExAthena.Memory (ExAthena v0.4.1)

Copy Markdown View Source

File-based project memory.

Loads AGENTS.md (preferred) / CLAUDE.md files from a small fixed hierarchy and turns them into messages the agent sees on every turn.

The hierarchy, in load order, is:

  1. User-level~/.config/ex_athena/AGENTS.md (or CLAUDE.md). Cross-project preferences a user wants every agent to honour.
  2. Project-level<cwd>/AGENTS.md (or CLAUDE.md). Repository conventions; usually committed.
  3. Local override<cwd>/AGENTS.local.md. Personal scratch on top of project conventions; usually gitignored.

When both AGENTS.md and CLAUDE.md exist at the same level, the AGENTS.md file wins (matches opencode's behaviour for cross-tool compatibility).

Where the messages live

Every loaded file becomes a single user-role message tagged name: "memory" — placed at the front of the conversation so it precedes the user's first prompt. The Claude Code paper notes that Claude Code delivers memory as user-context (probabilistic compliance) rather than as a system prompt (deterministic compliance), and we copy that pattern.

The compactor pipeline pins these messages: see ExAthena.Memory.pinned_count/1.

Summary

Functions

Discover and load the memory hierarchy for cwd. Returns a list of Message.t() in load order.

Is message a memory user-context message produced by discover/2?

Number of pinned-prefix slots the compactor must preserve for memory messages already prepended to messages. Used by ExAthena.Compactors.Summary (and the PR2 pipeline) to compute the effective floor for the pinned prefix.

Functions

discover(cwd, opts \\ [])

@spec discover(
  String.t(),
  keyword()
) :: [ExAthena.Messages.Message.t()]

Discover and load the memory hierarchy for cwd. Returns a list of Message.t() in load order.

Each file's contents are wrapped with a header that names the source so the model can tell them apart. Empty / missing files are skipped.

Options

  • :user_dir — override the user-level memory directory. Defaults to ~/.config/ex_athena/. Useful in tests.
  • :filenames — override the candidate filenames (defaults to ["AGENTS.md", "CLAUDE.md"]).

memory_message?(arg1)

@spec memory_message?(ExAthena.Messages.Message.t() | term()) :: boolean()

Is message a memory user-context message produced by discover/2?

pinned_count(messages)

@spec pinned_count([ExAthena.Messages.Message.t()]) :: non_neg_integer()

Number of pinned-prefix slots the compactor must preserve for memory messages already prepended to messages. Used by ExAthena.Compactors.Summary (and the PR2 pipeline) to compute the effective floor for the pinned prefix.