Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"name": "lore",
"source": "./",
"description": "Shared memory for Claude Code, Codex, and DOXA: capped curated facts, evidence-backed beliefs, FTS5 session search, staged review, learned skills, and signed sync.",
"version": "0.62.19"
"version": "0.62.20"
}
]
}
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lore",
"description": "Memory for Claude Code that reasons about you and improves itself: Honcho-pattern belief store with deriver, dreamer and dialectic (/lore:ask), automatic skillification with a closed judge/update/retire loop, on a Hermes-pattern core \u2014 hard-capped curated memory, FTS5 session search, staged review.",
"version": "0.62.19",
"version": "0.62.20",
"author": {
"name": "Fabian Wilde",
"email": "docwilde@proton.me"
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 0.62.20 — 2026-10-09

**Reviewed codegraph snapshots**

- Add **`codegraph_snapshot_read_v1`** for worktree-scoped Rust syntax snapshots. Reads recheck the requested source hash and return unknown binding; other-file candidates remain unverified.
- Add **`codegraph_snapshot_store_v1`** and **`lore-rs codegraph store`** with terminal review and revision checks. Snapshots stay local; no TUI background write or sync occurs.

## 0.62.19 — 2026-10-09

**Pending summary completeness**
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 55 additions & 0 deletions docs/codegraph-snapshots.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Codegraph snapshot store

LORE can retain one reviewed DOXA syntax answer per exact Git worktree,
file, and query kind. This is a local, data-only cache. It does not resolve
Rust imports or calls, turn syntax candidates into facts, sync snapshots,
or put codegraph data into an agent's context.

## Protocol

`codegraph_snapshot_read_v1` accepts
`{"op":"codegraph_snapshot_read_v1","cwd":"/absolute/worktree", "query":"file|imports|calls|modules","path":"src/lib.rs"}`.
It returns `{"status":"missing"}` or a `current` result with the stored
`graph`, revision, source and graph SHA-256, and explicit
`binding: "unknown"`, `freshness: "requested_source_verified_only"`.
An edited, unreadable, or symlinked requested source fails closed instead of
returning graph data. Read creates no store files.

`codegraph_snapshot_store_v1` adds `expected_revision` and the exact JSON
from `doxa codegraph --lore-map ...`. Only a trusted `HumanReview` carrier may
call it; `Model`, `Derived`, and ordinary `Interactive` authority are refused.
Revision `0` creates, and each later write must name the current revision.
The graph's project, absolute worktree, query, path, and requested-source hash
must match the current source bytes. Writes are locked and atomic. The
LORE file-map overlay in the DOXA export is checked for project scope but
is not stored: it has no revision or source hash and must be read afresh.
The export's `query_sha256` is ignored because it hashes DOXA's original
struct serialization, whose field order is lost when LORE parses JSON. LORE
computes and verifies its own `graph_sha256` over the stored graph value.

For a terminal owner, export the DOXA answer to an owned file, inspect it,
compute that file's SHA-256, then run:

```sh
lore-rs codegraph store --cwd /absolute/worktree --input /absolute/export.json \
--expected-sha256 <export-file-sha256> --expected-revision 0
```

The command requires a terminal and a typed `STORE` confirmation. It is an
explicit review affordance, not a security boundary against another process
running as the same user. No TUI path writes automatically.

## Worktree lifecycle

The project key follows LORE's Git project identity, but the snapshot key also
binds the exact worktree path and its Git marker. Linked worktrees remain
separate even when they share a project key. Removing a worktree makes its
snapshot unreadable; recreating at the same path gets a new identity and
returns `missing`. Replacing the main checkout's `.git/config` also invalidates
its snapshots conservatively. Orphan files stay local until an explicit owner
cleanup policy is designed; this operator never guesses that a worktree was
deleted and never silently migrates an old snapshot.

Only the requested source file is rehashed. Candidates from other files can
change independently; their saved hashes and ambiguity remain in the graph,
but the operator never claims that they are current or semantically bound.
4 changes: 4 additions & 0 deletions docs/native-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ search, sync state and local sync records. Agent operators use the same core
with a frozen engine, session and project identity. Learned skill selection,
usage and outcomes use the existing skill layout.

The [codegraph snapshot store](codegraph-snapshots.md) adds an explicit,
source-checked read operator and owner-reviewed local write gate. It does not
alter curated memory or the sync protocol.

The native review worker proves the transcript's identity and bytes before
calling a provider and again before applying output. It derives beliefs and
stages memory, file map and skill proposals. Reconciliation freezes candidate
Expand Down
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "lore",
"version": "0.62.19",
"version": "0.62.20",
"description": "Unified user, repo, and session memory for Claude Code, Codex, and DOXA",
"author": {
"name": "Dr. Fabian Wilde",
Expand Down
2 changes: 1 addition & 1 deletion rust/lore-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "lore-core"
version = "0.62.19"
version = "0.62.20"
edition = "2021"
license = "AGPL-3.0-only"
description = "Native LORE memory, beliefs, review and session index"
Expand Down
44 changes: 43 additions & 1 deletion rust/lore-core/src/bin/lore-rs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Native JSONL carrier. No Python interpreter, fallback or JSON authority.
use lore_core::{config::Config, gate::Authority, Core, Error};
use serde_json::{json, Value};
use std::io::{self, BufRead, Read, Write};
use std::io::{self, BufRead, IsTerminal, Read, Write};
use std::time::Duration;

const AGENT_FRAME_BYTES: usize = 64 * 1024;
Expand Down Expand Up @@ -36,6 +36,9 @@ fn main() {
memory_show(options)
}
[group, command] if group == "filemap" && command == "show" => filemap_show(),
[group, command, options @ ..] if group == "codegraph" && command == "store" => {
codegraph_store(options)
}
_ => lore_core::standalone::run(&args),
};
if let Err(error) = outcome {
Expand Down Expand Up @@ -144,6 +147,45 @@ fn write_frame(output: &mut impl Write, reply: &Value, limit: usize) -> lore_cor
Ok(())
}

/// Explicit owner path: review the exact exported file digest in a terminal.
/// The JSONL bridge never receives this authority from its request body.
fn codegraph_store(options: &[String]) -> lore_core::Result<()> {
if !io::stdin().is_terminal() || !io::stderr().is_terminal() {
return Err(Error::Untrusted);
}
let [cwd_flag, cwd, input_flag, input, expected_flag, expected,
revision_flag, revision] = options else {
return Err(Error::InvalidRequest);
};
if cwd_flag != "--cwd" || input_flag != "--input" || expected_flag != "--expected-sha256"
|| revision_flag != "--expected-revision"
|| expected.len() != 64 || !expected.bytes().all(|byte| byte.is_ascii_hexdigit()) {
return Err(Error::InvalidRequest);
}
let revision = revision.parse::<u64>().map_err(|_| Error::InvalidRequest)?;
let bytes = lore_core::files::read_regular(std::path::Path::new(input), 96 * 1024)?;
if lore_core::digest(&bytes) != expected.to_ascii_lowercase() {
return Err(Error::Changed);
}
let snapshot: Value = serde_json::from_slice(&bytes).map_err(|_| Error::InvalidRequest)?;
let query = snapshot["graph"]["query"].as_str().ok_or(Error::InvalidRequest)?;
let path = snapshot["graph"]["value"].as_str().ok_or(Error::InvalidRequest)?;
let request = json!({"op":"codegraph_snapshot_store_v1","cwd":cwd,"query":query,
"path":path,"expected_revision":revision,"snapshot":snapshot});
eprint!("Store reviewed codegraph export SHA-256 {expected}? Type STORE to continue: ");
io::stderr().flush()?;
let mut confirmation = String::new();
io::stdin().read_line(&mut confirmation)?;
if confirmation.trim() != "STORE" { return Err(Error::Untrusted); }
let cfg = Config::from_env(Duration::from_secs(3))?;
let mut core = lore_core::Core::new(cfg, Authority::HumanReview {
agent: "lore-cli".into(), engine: "owner".into(),
});
let result = core.execute(&request)?;
println!("{}", serde_json::to_string(&result).map_err(|_| Error::Unavailable)?);
Ok(())
}

// Readback advertised by native context. These commands open only existing
// curated files/labels; they never initialize a database, lock or store.
const SHOW_BYTES: usize = 64 * 1024;
Expand Down
Loading
Loading