Skip to main content

A figure of shimmering cloud rising from a dark sea, weaving threads of light into a constellation of beliefs

aelfrice

Your AI stops forgetting. Set up once. Stays out of the way.

No cloud. No account. No telemetry.

PyPI Python License CI

You correct your agent. "Got it," it says. Next session, same mistake.

aelfrice runs in the background and stops the amnesia. Write a rule once and every relevant prompt thereafter ships with that rule already attached, before the model sees your message. There is no rules file to maintain and nothing for the agent to skip: the matched beliefs are in the prompt itself.

Built for developers using AI coding agents. Hosts that expose a UserPromptSubmit hook get first-class support — the hook is what makes the guarantee possible, since a tool the model chooses whether to call cannot put the right beliefs in front of it before it reads your message. Local-only by design — embeddings, vector RAG, and cloud sync are out of scope, and Philosophy explains why that trade-off is worth it.

Install

uv tool install aelfrice    # requires uv — https://docs.astral.sh/uv/
aelf setup                  # wire the UserPromptSubmit hook into your agent
aelf onboard .              # deterministic project scan (regex classifier). For LLM-quality with no API key, run /aelf:onboard in your agent.
aelf lock "never push directly to main; use scripts/publish.sh"

That's it. The next prompt that mentions "push" already has the rule. From here on out aelfrice is invisible — no command to remember to run, no file to keep updated.

Using Codex CLI? aelf setup --host codex wires the same hook set into $CODEX_HOME/~/.codex's hooks.json and ships the /aelf:* command bundle as $aelf-* agent skills (v4.1.0+) — see INSTALL § Codex host.

What you'll see

You type a message in your agent. aelfrice's hook fires before the model sees it and prepends matched beliefs as an <aelfrice-memory> block:

<aelfrice-memory>
The following are retrieved beliefs from the local memory store. ...
<belief id="a1f3c2d0" lock="user">never push directly to main; use scripts/publish.sh</belief>
<belief id="91e02d3c" lock="user">commits must be SSH-signed with ~/.ssh/id_ed25519</belief>
<belief id="77c01b2a">the publish script runs the release checks before tagging</belief>
</aelfrice-memory>

push the release

The model reads the whole thing as one message. Your rules arrive every relevant time, not when the agent decides to check a file.

What it does for you

Lock a rule once with aelf lock "..." and it comes back attached to every relevant prompt, in every future session. The reminding happens for you — and the model can't skip it, because the rule is already in the prompt when it starts reading rather than sitting in a file it may or may not consult.

There's also nothing to maintain. Passive capture logs and ingests every turn, and successful git commit messages too, so the memory grows while you work without you typing aelf at all.

And it all stays on your computer: one SQLite file, no cloud account, no telemetry. If you stop trusting aelfrice, aelf uninstall removes it in one command (--archive encrypts the DB to a file first).

Why not just a rules file?

A rules file is advice the agent may read; aelfrice is context the model has already read. And by Leonard Lin's bar, "a vector store with a similarity query" is not a memory system either — a memory system has to answer who wrote this, when, via what ingress, what supersedes it, and how do I take it back. aelfrice meets the four pillars (provenance, write gates, conflict handling, reversibility) directly. The side-by-side against hand-maintained rules files and vector stores lives in COMPARISON.md.

Day-to-day

After aelf setup you rarely type aelf again. The everyday surface:

aelf onboard .                      # once per project — deterministic scan (or /aelf:onboard for the no-key subagent flow)
aelf lock "never push to main"      # add a permanent rule
aelf locked                          # see what rules are active
aelf search "push to main"           # check what the agent will see
aelf status                          # quick health summary
aelf setup / aelf doctor            # initial install + verification
aelf feed                            # read the belief-write event log (v3.5+)
aelf stale --older-than 90 --cold-for 30   # surface forgotten beliefs (v3.5+)
aelf review --generate               # weekly keep / remove / lock checkpoint (v3.5+)

aelf --help shows the everyday surface; aelf --help --advanced lists the rest. Full reference: COMMANDS. The same operations are exposed as /aelf:* slash commands — same library underneath. See SLASH_COMMANDS.

How it works

Three retrieval lanes run on every prompt (a fourth, BFS graph expansion, is opt-in), the best matches get prepended to your prompt, and the model reads the lot as one message:

L0: locked beliefs   -> rules you marked permanent (always returned, never trimmed)
L2.5: entity index   -> deterministic NER-extracted entity lookup, exact + stem match
L1: FTS5 keyword     -> SQLite full-text search, BM25 + posterior-weighted rerank
L3: graph walk       -> typed-edge BFS from the L0+L2.5+L1 seed set (DERIVED_FROM, CONTRADICTS,
                        SUPERSEDES, RELATES_TO, ...) — opt-in: [retrieval] bfs_enabled = true

Illustrative schematic of aelfrice retrieval lanes over a belief graph: L0 locked beliefs pinned at the query, L1 FTS5/BM25 keyword seeds fanning out, the opt-in L3 typed-edge graph walk reaching outward hop by hop, and structural-HRR bridges leaping to vocab-gap matches.

Illustrative — not a trace of any real store. L0 locked rules always return; an FTS5/BM25 query seeds L1; the opt-in L3 graph walk steps along typed edges hop by hop; the separate structural-HRR lane (retrieve_v2) bridges to matches that share no vocabulary with the query. Color is the lane; distance from center is graph-walk depth. The L2.5 entity-index lane is omitted for legibility. Rendered by render_retrieval_lanes.py.

L0 always ships. L1, L2.5, and (when enabled) L3 are budget-trimmed against the merged candidate set in score-descending order; locked beliefs win every overflow. Default budget: 1,500 tokens per hook-injected prompt (the aelf search / library retrieve() default is 2,400). A separate structural-HRR lane (Plate-FFT bind/probe) routes queries that parse as structural markers in the retrieve_v2 API; ordinary prompts never touch it.

Your lock count doubles as a baseline-context budget: lock 200 things and every session opens with all 200, by design. Everything non-locked is BM25-ranked and budget-trimmed. The first prompt of a new session carries one extra block — a <session-start> sub-block listing all locks plus load-bearing unlocked beliefs (corroboration ≥ 2, or posterior mean ≥ ⅔ with α+β ≥ 4); subsequent prompts in the same session skip it.

Bench evidence on the labelled query-strategy corpus measured +0.2851 absolute NDCG@k (+94.8%) versus the v1.4 raw-BM25 baseline (v3.0 30-row corpus, 2026-05-12) at +0.96 ms p99 over legacy-bm25 (re-measured 2026-05-26; gate budget +5 ms delta). Measured on a labelled corpus that is not shipped in this repository, so the figure is not reproducible from a public clone; the in-repo gate tests/bench_gate/test_query_strategy.py skips without AELFRICE_CORPUS_ROOT and, when it does run, asserts only that uplift is positive rather than checking the quoted number. For figures reproducible on HEAD see the scripts under benchmarks/. Full lane wiring, composition, and federation peer DBs: ARCHITECTURE § Retrieval.

Memory model

Every belief carries a (α, β) Beta-Bernoulli posterior: α / (α+β) is the confidence; α + β is how much evidence backs that confidence. New beliefs sit at low evidence (high variance, retrievable but discounted); locked beliefs short-circuit decay and pin as ground truth.

You run It stores
aelf lock "never commit .env files" Permanent rule. Returned on every retrieval.
aelf onboard . Walks the project — git log, prose headings, code structure — and ingests structural facts as agent_inferred beliefs via the deterministic regex classifier.
/aelf:onboard Same scan, higher-quality classification driven by in-session subagents — no API key, no billing. The preferred path in an agent; bare aelf onboard is the deterministic fallback.
aelf feedback <id> used α += 1. Strengthens the belief's posterior.
aelf feedback <id> harmful β += 1. Weakens it. Locks resist passive feedback by design — change with aelf unlock / aelf delete.
aelf promote <id> Flips origin from agent_inferred to user_validated. With --to-scope <SCOPE>, also moves federation visibility (project / global / shared:<name>).
/aelf:wonder <topic> Researches the topic and writes the findings as speculative phantoms; /aelf:reason <topic> can then walk them.
(passive — no command) Default-on auto-capture: every prompt/response turn is logged and ingested at compaction; successful git commit events are ingested too. Opt out per-hook via aelf setup --no-transcript-ingest, --no-commit-ingest, --no-session-start, --no-stop-hook, --no-sessionstart-recap, --no-search-tool, --no-search-tool-bash, --no-pre-issue-guard, --no-claude-memory-mirror, --no-agent-context — see INSTALL § default-on hooks.

Each belief has an origin column tying it to the action that wrote it — one of user_stated, user_corrected, user_validated, user_transcript, agent_inferred, agent_remembered, document_recent, speculative, unknown. The store is a single SQLite file; open it in any browser, nothing is hidden.

Reasoning surfaces

Two slash commands let the agent reach back into the belief graph mid-turn, beyond the auto-injected retrieval block. They pair: /aelf:wonder grows the graph by researching; /aelf:reason walks the enriched graph for structured verdicts.

/aelf:wonder <topic> — the research surface. Given a topic, aelfrice runs gap analysis on what the store already knows, generates 2–6 orthogonal research axes (always-on domain_research + internal_gap_analysis; conditional contradiction_resolution / uncertainty_deep_dive / coverage_extension), has the host agent fan out one research task per axis to research and write up findings, then persists the merged research as new speculative beliefs via wonder_ingest. Those phantoms sit in the graph at low evidence — discoverable by retrieval and by the next /aelf:reason <topic> — until you promote them with aelf promote (or lock the underlying statement, which auto-promotes a matching phantom). Agent-count shorthand like quick 2-agent / deep 4-agent is recognised in the query string — the integer sets the agent count (quick / deep are optional qualifiers).

/aelf:reason <query> — the structured-walk surface. Walks the belief graph from BM25-seeded starting points and emits a typed reasoning trace: hops with edge-type breadcrumbs, a VERDICT (SUFFICIENT / PARTIAL / UNCERTAIN / INSUFFICIENT / CONTRADICTORY), IMPASSES (typed gaps, ties, or constraint failures), and SUGGESTED UPDATES(belief_id, direction, note) rows that map straight to aelf feedback so the conclusion closes the loop on the beliefs that fed it. Each impasse is dispatched by the host agent to a role-tagged worker (Verifier / Gap-filler / Fork-resolver). Peer hops in foreign federation scopes are annotated [scope:<name>].

They're meant to be used in that rhythm — /aelf:wonder adds fresh thinking to the graph, then /aelf:reason draws conclusions across it. Both surfaces are deterministic in the aelfrice layer (verdict classification, impasse derivation, axis generation, suggested-update mapping). The only LLM calls happen when the host agent dispatches one worker per impasse or research axis — and those calls run under the host's own credentials, not aelfrice's. Specs: COMMANDS § wonder, COMMANDS § reason.

What you get for free

Running in the background. No action required after aelf setup.

  • Passive capture. Ten default-on hooks: UserPromptSubmit retrieval, four-event transcript-ingest, PostToolUse:Bash commit-ingest, SessionStart locked-belief injection (with a belief-write recap line, v3.5+), Stop lock-prompt, PreToolUse:Grep|Glob memory-first search, PreToolUse:Bash memory-first search, the PreToolUse:Bash issue-dup guard, the PostToolUse:Write|Edit|MultiEdit claude-memory mirror (v3.7+; since v4.0, #1089, the one-shot reconcile at first aelf setup records per-project consent and the mirror runs from then on — opt out any time with AELFRICE_MIRROR_CLAUDE_MEMORY=0 or [memory] mirror_claude_memory = false, which always win over the consent sentinel), and the PreToolUse:Agent worker-context injection (dispatched workers inherit locked + task-relevant beliefs; opt out via --no-agent-context). Session activity flows into the belief graph without you typing aelf at all; opt out per-hook — see INSTALL § default-on hooks.
  • Determinism. SQLite + a deterministic numeric stack (numpy / scipy / snowballstemmer — no GPU, no network). No embeddings, no learned re-rankers, no LLM in the retrieval path. Every result traces to the action that wrote it.
  • Local-only. SQLite at <git-common-dir>/aelfrice/memory.db. Two outbound calls are on by default: the update notifier — a TTL-gated, read-only GET to https://pypi.org/pypi/aelfrice/json that transmits nothing (disable with AELF_NO_UPDATE_CHECK=1) — and the pre-issue duplicate guard, which runs gh issue list --search with tokens from your issue title, and only when you run gh issue create (disable with AELFRICE_NO_PRE_ISSUE_GUARD=1 or aelf setup --no-pre-issue-guard). No telemetry; no accounts. The memory/retrieval path never touches the network. (LLM dispatches in /aelf:wonder / /aelf:reason flows do reach the network — under the host agent's credentials, not aelfrice's; the retrieval path stays local.) Per-project isolation by construction. Read-only cross-project federation via knowledge_deps.json — peer DBs are opened read-only, foreign-id mutations are rejected at the API surface. See PRIVACY.md.
  • Removable. aelf uninstall --archive backup.aenc encrypts the DB to a file, then deletes it. Or --purge for a full wipe.

Obsidian export

If you already live in Obsidian, aelf export-obsidian <vault-path> emits the belief graph as one Markdown note per belief under <vault>/aelfrice/. Typed edges land in YAML front-matter for Dataview; the same edges appear in the note body as wikilinks so the graph view has something to draw. The export is one-way (DB → vault): SQLite stays the source of truth, and the <vault>/aelfrice/ subdirectory is wiped and rewritten on each run.

Scopes: --scope all (everything, capped by --max-notes), --scope recent (newest first), --scope query "<text>" (BM25 seeds + N-hop neighbourhood). Default cap is 500 notes; the hard ceiling is 5000 unless --force is passed.

Two structural limits, shipped with the feature: Obsidian's built-in graph view chokes around a few thousand nodes (bound the export with --scope query / --max-notes, or use aelf graph for query-anchored visualization at any store size), and the graph view is untyped — edge types are preserved in YAML front-matter and queryable via Dataview, but the graph view will not show them.

Status

Latest stable: v4.3.0 (2026-08-12). Per-entry detail in CHANGELOG § 4.3.0. Per-version history: docs/concepts/ROADMAP.md. Known limits: docs/user/LIMITATIONS.md.

OSSInsight

Reproducibility

Documentation

Citation

@software{aelfrice2026,
  author = {robotrocketscience},
  title  = {aelfrice: deterministic Bayesian memory for AI coding agents},
  year   = {2026},
  url    = {https://github.com/robotrocketscience/aelfrice},
  license = {MIT}
}

MIT

Release files for aelfrice 4.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aelfrice 4.3.0
File Size Uploaded
aelfrice-4.3.0.tar.gz 9.8 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for aelfrice 4.3.0
File Interpreter ABI Platform
aelfrice-4.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 10.9 MB

Release files / aelfrice-4.3.0.tar.gz

Download URL aelfrice-4.3.0.tar.gz
Size 9.8 MB
Tags Source
SHA-256 checksum
How to use checksums
24f37506b7b5c203a11c952f9324a6b2ae9db75f8b11763d56981b4d0b55be97
BLAKE2b-256 checksum
How to use checksums
4fc470b9aae4420fd2f5f0245d520fa5227413aaa3f5bd07cbcca83b96ec78d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.

Transparency log

Release files / aelfrice-4.3.0-py3-none-any.whl

Download URL aelfrice-4.3.0-py3-none-any.whl
Size 1.1 MB
Tags Python 3
SHA-256 checksum
How to use checksums
17df460efdb9bc0db74e5be98fc75dfbea3d2ec951d2f4804aaefc581fdc2faa
BLAKE2b-256 checksum
How to use checksums
9e4d18ab2e4ef78de65634dea740557d927fd1e1696ca05e8c48d6379f1e571b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.

Transparency log

Release history Release notifications | RSS feed

5.0.0

2 release files

This release

4.3.0 This release

2 release files

4.2.0

2 release files

4.1.0

2 release files

4.0.0

2 release files

3.8.0

2 release files

3.7.0

2 release files

3.6.0

2 release files

3.5.1

2 release files

3.5.0

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.1

2 release files

3.0.0

2 release files

2.1.0

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.6.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page