Skip to content

Repository files navigation

Chronicle Engine · OpenClaw Memory Plugin

Remote-authority memory for OpenClaw, with a Rust backend as the only supported runtime authority.

English | 简体中文

1. What This Plugin Is

Chronicle Engine is not a local memory database embedded inside the plugin anymore.

The supported model is:

  • the Rust backend owns memory authority
  • the plugin owns OpenClaw integration and prompt-time orchestration
  • the client/runtime provides authenticated principal identity

In practical terms:

  • storage happens in the backend
  • retrieval and ranking happen in the backend
  • scope and ACL happen in the backend
  • prompt injection and session-local dedupe stay in the plugin
  • backend-facing recall filter semantics stay in the backend; the plugin only keeps prompt-time orchestration and rendering

2. Architecture At A Glance

 +--------------------------------------+
| OpenClaw Runtime |
| hooks, tools, lifecycle events |
+-------------------+------------------+
|
v
+----------------------------------------+
| Chronicle Engine Plugin |
| index.ts |
| src/backend-client/* |
| src/backend-tools.ts |
| src/context/* |
+-------------------+--------------------+
|
data-plane HTTP | prompt-time orchestration
+ auth headers | session-local state only
|
v
+---------------------------------------------+
| Rust Remote Memory Backend |
| backend/src/* |
| LanceDB + SQLite |
| retrieval / ranking / scope / ACL / jobs |
+---------------------------------------------+

3. Ownership Split

Backend vs plugin

ConcernBackend (backend/src/*)Plugin (index.ts, src/backend-client/*, src/context/*)
Memory persistenceOwnsDoes not own
Recall candidate generationOwnsDoes not own
Ranking / rerank / MMR / decayOwnsDoes not own
Scope derivation / ACLOwnsMust not reconstruct
Auto-capture write acceptance + persistenceOwnsOnly forwards runtime payloads
Behavioral-guidance recall retrievalOwnsOnly plans prompt-time autoRecall guidance injection
Distill job executionOwnsOnly enqueues / polls
Distill source cleaning / artifact persistenceOwnsDoes not own
Distill lesson/governance derivationOwnsDoes not own
Debug recall / distill status surfacesOwnsOnly calls typed client adapters
Hook registrationDoes not ownOwns
Backend DTO transport adaptersDoes not ownOwns
Prompt block renderingDoes not ownOwns
Session-local exposure suppressionDoes not ownOwns
Fail-open vs fail-closed route behaviorShared contract, backend-enforced + plugin-handledOwns runtime behavior at hook/tool boundary

Old mental model vs current model

QuestionOld local-authority modelCurrent supported model
Where is the source of truth?Local TS modulesRemote Rust backend
Can the plugin decide scopes?Historically yesNo
Can the plugin rank final backend-visible rows authoritatively?Historically yesNo
Can the plugin shape prompt injection locally?YesYes
Is there a supported local fallback memory engine?Historically yesNo

4. Admin Plane

Chronicle Engine includes a bundled Admin Plane for operators to manage memories, monitor distillation, and trace recall logic.

  • URL: Accessible at /admin on the backend host.
  • Auth: Protected by a dedicated auth.admin.token (bearer auth).
  • Features:
    • Dashboard: Overview of active principals and their activity stats.
    • Memories: Browse and manage memory rows for any principal.
    • Behavioral Guidance: Inspect active behavioral rules.
    • Recall Lab: Side-effect-free recall simulation with full debug traces.
    • Distill Jobs: Monitor background knowledge distillation status and artifacts.
    • Transcripts: View session transcripts for context analysis.
    • Governance: Review and promote candidate memories derived from distillation.
    • Audit Log: Track admin-plane mutations and configuration changes.
    • Settings: Edit and persist backend TOML configuration, with explicit restart-required feedback.

The Admin UI is a React SPA bundled into the backend binary and served directly by the Rust service.

Runtime vs admin tokens

The backend requires two separate bearer tokens in backend.toml:

[auth.runtime]
token = "replace-with-runtime-bearer-token"
[auth.admin]
token = "replace-with-admin-bearer-token"
  • auth.runtime.token is only for /v1/* data-plane requests.
  • auth.admin.token is only for /admin/api/* admin-plane requests.
  • Both use Authorization: Bearer <token>.
  • They are intentionally not interchangeable.

For Docker deployments, the image already contains a default backend.toml. The recommended override path is Docker Compose environment: keys using nested TOML paths with double underscores, for example:

environment:
AUTH__RUNTIME__TOKEN: "${RUNTIME_TOKEN}"AUTH__ADMIN__TOKEN: "${ADMIN_TOKEN}"PROVIDERS__EMBEDDING__API_KEY: "${EMBEDDING_API_KEY}"

Common Docker Compose overrides:

Environment variableTOML keyPurposeExpected formatExample
AUTH__RUNTIME__TOKENauth.runtime.tokenBearer token for /v1/* data-plane requestsnon-empty stringAUTH__RUNTIME__TOKEN=prod-runtime-token
AUTH__ADMIN__TOKENauth.admin.tokenBearer token for /admin/api/* admin-plane requestsnon-empty stringAUTH__ADMIN__TOKEN=prod-admin-token
SERVER__BINDserver.bindBackend listen address inside the containerhost:port stringSERVER__BIND=0.0.0.0:8080
SERVER__ADMIN_ASSETS_PATHserver.admin_assets_pathFilesystem path to bundled admin SPA assetsabsolute path stringSERVER__ADMIN_ASSETS_PATH=/usr/local/bin/web/dist
STORAGE__LANCEDB_PATHstorage.lancedb_pathLanceDB data directoryabsolute path stringSTORAGE__LANCEDB_PATH=/var/lib/chronicle-engine-backend/lancedb
STORAGE__SQLITE_PATHstorage.sqlite_pathSQLite job/audit database pathabsolute path stringSTORAGE__SQLITE_PATH=/var/lib/chronicle-engine-backend/sqlite/jobs.db
LOGGING__LEVELlogging.levelBackend log verbositystring such as trace / debug / info / warn / errorLOGGING__LEVEL=info
PROVIDERS__EMBEDDING__BASE_URLproviders.embedding.base_urlEmbedding provider base URLURL stringPROVIDERS__EMBEDDING__BASE_URL=https://api.openai.com/v1
PROVIDERS__EMBEDDING__MODELproviders.embedding.modelEmbedding model idstringPROVIDERS__EMBEDDING__MODEL=text-embedding-3-small
PROVIDERS__EMBEDDING__APIproviders.embedding.apiEmbedding provider API flavorstring such as openai / builtinPROVIDERS__EMBEDDING__API=openai
PROVIDERS__EMBEDDING__API_KEYproviders.embedding.api_keyEmbedding provider API keynon-empty stringPROVIDERS__EMBEDDING__API_KEY=sk-...
PROVIDERS__RERANK__ENABLEDproviders.rerank.enabledEnable or disable provider-backed rerankboolean true / falsePROVIDERS__RERANK__ENABLED=false

Path-style rule:

  • Use TABLE__SUBTABLE__KEY to map an environment variable to a nested TOML key.
  • Strings stay plain strings.
  • Booleans use true or false.
  • Numbers use normal integer or float literals.
  • Unknown path-style variables are ignored.

Post-deploy smoke checks

cd /root/.openclaw/workspace/plugins/openclaw-chronicle-engine
git rev-parse --short HEAD
docker compose -f deploy/docker-compose.yml config >/dev/null
curl -fsS http://127.0.0.1:8080/admin >/dev/null
curl -fsS \
-H "Authorization: Bearer $ADMIN_TOKEN" \
http://127.0.0.1:8080/admin/api/settings/runtime-config
curl -fsS \
-H "Authorization: Bearer $RUNTIME_TOKEN" \
-H "X-OpenClaw-User-Id: smoke-user" \
-H "X-OpenClaw-Agent-Id: smoke-agent" \
-H "Content-Type: application/json" \
-d '{"query":"smoke check","topK":3}' \
http://127.0.0.1:8080/v1/recall/generic
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "X-OpenClaw-User-Id: smoke-user" \
-H "X-OpenClaw-Agent-Id: smoke-agent" \
-H "Content-Type: application/json" \
-d '{"query":"should fail","topK":1}' \
http://127.0.0.1:8080/v1/recall/generic
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer $RUNTIME_TOKEN" \
http://127.0.0.1:8080/admin/api/settings/runtime-config

Expected:

  • git rev-parse prints the deployed commit.
  • /admin returns the bundled SPA shell.
  • admin token can read /admin/api/settings/runtime-config.
  • runtime token can call /v1/recall/generic.
  • admin token must not succeed on /v1/*.
  • runtime token must not succeed on /admin/api/*.

Extended distill and settings checks

Settings save is persisted atomically but still requires restart to take full effect.

curl -fsS \
-X PUT \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d @- \
http://127.0.0.1:8080/admin/api/settings/runtime-config <<'JSON'{"configToml":"[server]\nbind = \"0.0.0.0:8080\"\nadmin_assets_path = \"/usr/local/bin/web/dist\"\n\n[storage]\nlancedb_path = \"/var/lib/chronicle-engine-backend/lancedb\"\nsqlite_path = \"/var/lib/chronicle-engine-backend/sqlite/jobs.db\"\n\n[auth.runtime]\ntoken = \"replace-with-runtime-bearer-token\"\n\n[auth.admin]\ntoken = \"replace-with-admin-bearer-token\"\n\n[logging]\nlevel = \"info\"\n\n[providers.embedding]\nbase_url = \"https://api.openai.com/v1\"\nmodel = \"text-embedding-3-small\"\napi = \"openai\"\napi_key = \"replace-with-embedding-api-key\"\n\n[providers.rerank]\nenabled = false\n"}JSON
curl -fsS \
-H "Authorization: Bearer $RUNTIME_TOKEN" \
-H "X-OpenClaw-User-Id: smoke-user" \
-H "X-OpenClaw-Agent-Id: smoke-agent" \
-H "Content-Type: application/json" \
-d '{"source":{"type":"inline_messages","messages":[{"role":"user","content":"I prefer concise release checklists."},{"role":"assistant","content":"Keep release verification short and explicit."}]},"mode":"session_lessons","persistMemoryRows":true}' \
http://127.0.0.1:8080/v1/distill/jobs

Expected:

  • settings save returns success plus restartRequired: true or restart_required: true.
  • distill enqueue returns a job id.
  • the job id can then be inspected with GET /v1/distill/jobs/{jobId}.

5. Request Flow

Generic recall

User prompt
-> OpenClaw hook
-> Chronicle Engine planner
-> backend client
-> POST /v1/recall/generic
-> backend retrieves + ranks + filters
-> plugin receives authoritative rows
-> local prompt block rendering
-> <relevant-memories> injected into prompt

Admin Access

Operator browser
-> GET /admin
-> backend serves SPA shell + assets
-> SPA requests /admin/api/* with admin bearer
-> backend validates admin token + rate limits
-> Operator manages memories / traces recall

Cadence-driven distill flow

agent_end
-> plugin appends ordered transcript rows
-> backend persists session transcript
-> every distill.everyTurns user turns
-> plugin enqueues POST /v1/distill/jobs
-> backend derives distill artifacts from session trajectory
-> later recall/injection can read persisted rows and artifacts

Distill job flow

distill request
-> plugin/backend client
-> POST /v1/distill/jobs
-> backend validates actor + source + mode
-> backend enqueues async distill job
-> backend cleans transcript/messages and builds deterministic span/window candidates
-> backend persists English distill artifacts
-> optional memory-row persistence
-> GET /v1/distill/jobs/{jobId} to inspect status/result

5. Old TS RAG vs Current Rust Remote RAG

Capability comparison

CapabilityOld TS-heavy chainCurrent Rust remote chainCurrent status
Persistence authorityLocal TS modules owned writes and storageRust backend owns writes and storageReplaced
Vector retrievalLocal TS implementationRust backendReplaced
Lexical / BM25-style retrievalLocal TS implementationRust backendReplaced
Hybrid mergeLocal TS implementationRust backendReplaced
RerankLocal TS implementationRust backendReplaced
Rerank fallback / key rotationLocal TS implementationRust backendReplaced
Recency / decay / length weightingLocal TS implementationRust backendReplaced
Access reinforcement time-decayHistorical TS-side capabilityRust backendPresent
Diversity / MMRHistorical TS-side capabilityRust backendPresent
Behavioral-guidance recall authorityLocal TS + local persistence pathRust backend recall path with plugin-side autoRecall behavioral renderingReplaced
Command-triggered trajectory-derived generationLocal/plugin-coupled executionRemoved; cadence-driven distill is the only supported generation pathRemoved
Distill async jobsHistorical sidecar/example pipelineRust backend distill jobsPresent, backend-native deterministic runtime
Scope derivation / ACLLocal TS participation existed historicallyRust backend onlyReplaced
Inspectable retrieval traceHistorical TS had thicker telemetry objectsRust backend debug trace routesAcceptable parity, not 1:1 shape recreation
Prompt injection renderingLocal TSLocal TSIntentionally retained
Session-local exposure suppressionLocal TSLocal TSIntentionally retained
Final generic auto-recall trimmingLocal TSLocal TS over backend-returned rowsLimited to direct prompt injection truncation

What was not recreated 1:1

Historical TS shapeCurrent replacement
Thick local telemetry object modelbackend debug trace routes with structured stages/fallback/counts/final row ids
Local authority ranking chainbackend-owned ranking chain
Local scope authority helpersbackend principal + scope authority

6. Has Old TS Been Fully Removed?

No, but the answer needs precision:

  • old TS local-authority runtime: removed
  • TS prompt-local orchestration: intentionally retained

Removed old local-authority modules

Removed pathWhy removed
src/store.tslocal persistence authority removed
src/retriever.tslocal retrieval authority removed
src/embedder.tslocal embedding authority removed
src/chunker.tsunused local chunking helper removed after import-proof showed no active runtime or test dependency
src/tools.tsold local-authority tool path removed
src/migrate.tsold local migration path removed
src/scopes.tslocal scope authority removed
src/access-tracker.tsold local access-metadata authority removed
cli.tsold local CLI path removed

Retained TS modules and why they still exist

Retained pathWhy it remains
src/context/*prompt-time orchestration only
src/context/recall-engine.tslocal gating / dedupe / exposure-state helpers
src/context/adaptive-retrieval.tsprompt-side retrieval trigger heuristic

Practical interpretation

If the question is:

  • “Is the old TS authority chain still alive?” -> No
  • “Does the repo still contain TS files related to recall/behavioral guidance?” -> Yes, intentionally, for prompt-local orchestration and tests

7. Runtime Rules That Matter

Principal identity contract

Remote data-plane calls require real runtime principal identity:

  • userId
  • agentId

Behavior by path:

Path typeIf principal identity is missing
Recall / prompt injectionSkip fail-open
Write / update / deleteFail closed
Auto-captureFail closed
List / statsFail closed
Distill enqueueFail closed

Scope contract

The plugin does not submit a target scope.

That means:

  • callers do not choose target scope in tool payloads
  • backend derives and enforces visibility
  • client-side scope reconstruction is not part of the supported architecture

8. Supported Features

CapabilityStatusNotes
Remote backend authorityYesRequired for supported runtime behavior
Hybrid retrievalYesBackend-owned
Provider-backed embeddingsYesBackend-owned
Rerank + fallbackYesBackend-owned
Time decay + access reinforcementYesBackend-owned
Diversity / MMRYesBackend-owned
Auto-recall prompt injectionYesLocal orchestration over backend recall
AutoRecall behavioral-guidance planningYesRead-only behavioral recall in backend, prompt-local guidance injection in plugin
Distill job enqueue + pollingYesBackend-owned async job surface
Distill inline-message cleaning + artifact persistenceYesBackend-owned execution path
Distill session-transcript sourceYesBackend-owned transcript persistence + async distill execution
Automatic distill every N user turnsYesRuntime cadence over backend-native session-transcript jobs
session-lessons modeYesOwns lesson, cause, fix, prevention, stable decision, and durable practice extraction
governance-candidates modeYesOwns worth-promoting learnings, skill extraction candidates, and AGENTS/SOUL/TOOLS promotion candidates
Distill artifact subtypesYesfollow-up-focus and next-turn-guidance replace separate derived/open-loop reflection persistence
memory_store / memory_update / memory_forgetYesRemote-backed
memory_list / memory_statsYesOptional management tools
memory_distill_enqueue / memory_distill_statusYesOptional management tools for caller-scoped backend distill jobs
memory_recall_debugYesOptional management/debug tool for explicit recall trace inspection
Local memory-pro CLINoRemoved
Supported local-authority runtimeNoRemoved

9. Backend Public Surface

If you need the shortest possible description of what the backend does today, it is this:

  • it owns all durable memory writes, updates, deletes, list/stats reads, and recall retrieval
  • it owns ranking, rerank fallback, MMR, time-decay, access reinforcement, and scope / ACL enforcement
  • it owns behavioral-guidance recall rows and the caller-scoped debug recall trace surfaces
  • it owns transcript persistence and async distill jobs, including artifact persistence and optional distilled memory-row persistence

The public backend route families that matter operationally are:

Route familyPurpose
/v1/memories/store, /update, /delete, /list, /statscaller-scoped memory write/read management
/v1/recall/genericordinary runtime recall
/v1/recall/behavioralbackend-managed behavioral-guidance recall
/v1/debug/recall/generic, /behavioralexplicit retrieval trace inspection
/v1/session-transcripts/appendpersist ordered runtime transcript rows
/v1/distill/jobs and /v1/distill/jobs/{jobId}enqueue and inspect async distill jobs

Two nearby concepts are easy to confuse but are intentionally different:

  • behavioral recall reads backend-managed behavioral rows for prompt-time guidance injection
  • distill derives artifacts, and optionally distilled memory rows, from transcript or inline-message sources

10. What The Plugin Explicitly Does Not Own

The plugin still has important runtime code, but it is not allowed to act as a second authority.

The plugin does not own:

  • durable persistence
  • authoritative retrieval / ranking / rerank decisions
  • scope derivation or ACL visibility decisions
  • backend-facing recall filter semantics
  • a separate sidecar or queue-file distill pipeline

The plugin does own:

  • OpenClaw hook and tool integration
  • backend transport / DTO adapters
  • prompt-time planning, rendering, and session-local exposure suppression

11. Distill: Old Sidecar vs Current Backend-Native Direction

ConcernHistorical jsonl_distill.py / sidecar pipelineCurrent backend-native direction
Job ownershipExternal script + workerRust backend job surface
Source preprocessingScript-local filtering/cleanupBackend cleanup/filtering pipeline
Reduction qualitySidecar reduction pipelineDeterministic Rust turns-stage lesson reducer
PersistenceExternal import back into storageBackend-owned artifacts and optional memory persistence
Status inspectionQueue files / external worker logsGET /v1/distill/jobs/{jobId}
Runtime authorityNot canonical anymoreCanonical direction

Current runtime shape:

  • runtime appends ordered transcript rows to backend on agent_end
  • runtime may optionally enqueue one backend-native session-transcript distill job every configured distill.everyTurns user turns
  • backend resolves the source rows, cleans them, builds deterministic span/window candidates, merges overlapping evidence, and persists artifacts
  • when persistMode=persist-memory-rows, backend also persists distilled memory rows from the final artifacts

Current behavior boundary:

  • the old jsonl_distill.py / example-worker sidecar path has been removed from the active repo runtime
  • it is not the supported runtime path
  • the supported direction is backend-native distill jobs backed by persisted session transcript rows
  • distill summaries in the current runtime are intentionally English-only and deterministic
  • optional runtime cadence can enqueue one session-transcript distill job every configured distill.everyTurns user turns

What current distill is good at:

  • deterministic turns-stage lesson extraction without sidecar infrastructure
  • multi-message evidence aggregation inside backend reduction windows
  • evidence-gated promotion of stable decision / durable practice rather than single-keyword escalation
  • stable artifacts and optional memory persistence under the same caller-scoped backend authority model
  • keeping all new-learning writes under session-lessons and governance-candidates

What current distill is intentionally not:

  • language-adaptive extraction
  • a separate non-distill generation pipeline
  • a restored queue-file / worker / memory-pro import architecture

12. Debuggability

Chronicle Engine now has two layers of observability:

SurfacePurposeContract stability
/v1/recall/*ordinary runtime recallstable data-plane DTOs
/v1/debug/recall/*inspect retrieval tracesexplicit debug surface, separate from ordinary DTO rows

Important boundary:

  • ordinary recall DTOs do not expose raw score-breakdown internals
  • debug trace routes exist so debugging gets richer visibility without bloating runtime contracts
  • memory_recall_debug is the management-gated tool surface for those debug routes

13. Install

Clone into the OpenClaw plugin workspace

git clone https://github.com/furedericca-lab/chronicle-engine.git ~/.openclaw/workspace/plugins/chronicle-engine
cd~/.openclaw/workspace/plugins/chronicle-engine
npm install

Slot it as the memory plugin

{
"plugins": {
"load": {
"paths": ["plugins/chronicle-engine"]
},
"entries": {
"chronicle-engine": {
"enabled": true,
"config": {}
}
},
"slots": {
"memory": "chronicle-engine"
}
}
}

Verify the slot

openclaw gateway restart
openclaw plugins info chronicle-engine
openclaw config get plugins.slots.memory

14. Minimal Supported Configuration

Use this as plugins.entries.chronicle-engine.config.

{
"remoteBackend": {
"enabled": true,
"baseURL": "http://127.0.0.1:8080",
"authToken": "${MEMORY_BACKEND_TOKEN}",
"timeoutMs": 10000,
"maxRetries": 1,
"retryBackoffMs": 250
}
}

Required fields:

FieldRequiredMeaning
remoteBackend.enabledYesMust be true
remoteBackend.baseURLYesBackend base URL
remoteBackend.authTokenYesRuntime bearer token
timeoutMsNoRequest timeout
maxRetriesNoTransport retry count
retryBackoffMsNoRetry backoff

Cutover note:

  • 1.0.0-beta.0 removes migration-only config aliases.
  • Only sessionStrategy: "autoRecall" | "systemSessionMemory" | "none" is supported.
  • Use autoRecallBehavioral.* as the canonical behavioral-guidance config surface.
  • Use governance.* for backlog/review workflow configuration.
  • Legacy pre-closeout config aliases are rejected.

15. Tools

Core tools

  • memory_recall
  • memory_store
  • memory_forget
  • memory_update
  • governance_log

Optional management tools

Enable enableManagementTools: true to expose:

  • memory_list
  • memory_stats
  • memory_distill_enqueue
  • memory_distill_status
  • memory_recall_debug
  • governance_review
  • governance_extract_skill

Management/debug tools stay caller-scoped and require runtime principal identity. They are not available as anonymous local fallbacks.

Backend client management/debug surfaces

The plugin client also has backend job adapters for:

  • distill jobs
  • recall debug traces (generic and behavioral)

16. Repository Layout

backend/ Rust backend implementation
docs/runtime-architecture.md
docs/archive/ historical plans and closed scopes
src/backend-client/* transport + DTO adapter
src/backend-tools.ts tool bridge
src/context/* prompt-time orchestration
test/* plugin-side tests

17. Testing

Plugin tests

npm test

Backend tests

cargo test --manifest-path backend/Cargo.toml --test contract_semantics -- --nocapture

18. Common Misunderstandings

“Is this still a local LanceDB plugin?”

No. The supported runtime model is remote authority only.

“Does src/context/* mean local authority still exists?”

No. src/context/* is prompt-time orchestration:

  • when to recall
  • how to render injected blocks
  • how to suppress repeated exposure in the same session

It is not backend ownership.

“Do old config aliases still work?”

No. Use the current schema names only:

  • sessionStrategy
  • autoRecallBehavioral.*
  • governance.*

“Does distill still mean running the old jsonl_distill.py sidecar?”

No. That sidecar path has been removed from the active runtime and the repo.

The supported direction is:

  • backend-native distill jobs
  • backend-owned status
  • backend-owned artifacts
  • backend-owned session transcript persistence and replay-safe source resolution

The old sidecar/example pipeline is not the canonical runtime path.

19. References

  • Runtime architecture: docs/runtime-architecture.md
  • Docs index: docs/README.md
  • Historical execution and closed scopes: docs/archive/
  • Plugin schema: openclaw.plugin.json

License

MIT

About

Historical memory engine for OpenClaw with remote backend authority and local context orchestration.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages