Skip to content

Commit e97c2f5

Browse files
committed
feat: v3.2.0 - cumulative metrics, interactive setup, and architect prompts
1 parent b52b8b0 commit e97c2f5

12 files changed

Lines changed: 222 additions & 63 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# LedgerMind
22

3-
**v3.1.3** · Autonomous Memory Management System for AI Agents
3+
**v3.2.0** · Autonomous Memory Management System for AI Agents
44

55
> *LedgerMind is not a memory store — it is a living knowledge core that thinks, heals itself, and evolves without human intervention.*
66

docs/changelogs/index.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ All notable changes to the LedgerMind project since version 2.0.0.
44

55
---
66

7+
## [v3.2.0] - 2026-03-02
8+
9+
- **Cumulative Metrics:** Implemented a zero-footprint mathematical model for
10+
incremental lifecycle updates.
11+
- **Interactive Setup:** Added model selection and automated 60s validation
12+
during project initialization.
13+
- **Architect Standards:** Upgraded documentation prompts to professional AI
14+
Architect and Principal Engineer levels.
15+
- **Integrity Stability:** Fixed a critical core bug in UnboundLocalError
16+
during file validation.
17+
718
## [v3.1.3] - 2026-03-02
819

920
- **Real-Time Synchronization:** Instant history synchronization for Claude

docs/changelogs/latest.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
# Latest Release: v3.1.3
1+
# Latest Release: v3.2.0
22

33
## March 2, 2026
44

5-
LedgerMind v3.1.3 focus on real-time synchronization, hypothesis unification,
6-
and improved technical log recording.
5+
LedgerMind v3.2.0 focus on architectural scalability through cumulative metrics
6+
and enhanced interactive configuration.
77

88
### Highlights
99

10-
- **Real-Time Synchronization (Stop Hook):** Instant history synchronization
11-
for Claude Code via the new `Stop` hook, preventing duplicate entries.
12-
- **Hypothesis Unification:** Consistent evolutionary path for both
13-
procedural and behavioral hypotheses.
14-
- **Increased Scaling:** Memory event length limit increased to 500KB to
15-
support large technical logs and complex code snippets.
16-
- **Secure Hook Recording:** Robust interaction recording via stdin pipes.
10+
- **Cumulative Metrics:** Mathematical model for incremental stability and
11+
frequency updates without storing historical event IDs.
12+
- **Interactive Model Selection:** Specify and validate custom models (e.g.,
13+
`gemini-2.0-flash`) directly during project initialization.
14+
- **Architect Prompts:** New high-standard documentation templates for
15+
knowledge enrichment.
16+
- **Bug Fixes:** Resolved critical UnboundLocalError in core integrity checks.
1717

18-
[View full v3.1.3 changelog](./v3.1.3.md)
18+
[View full v3.2.0 changelog](./v3.2.0.md)

docs/changelogs/v3.2.0.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Changelog v3.2.0 (March 2, 2026)
2+
3+
LedgerMind v3.2.0 introduces a major architectural shift to a fully cumulative
4+
metrics model, interactive model management, and professional documentation
5+
standards.
6+
7+
## Highlights
8+
9+
### 📉 Cumulative Metrics Model
10+
- **Zero-Footprint Storage:** Implemented a mathematical model for incremental
11+
metric updates. The system no longer needs to store long lists of event IDs
12+
in Markdown metadata, keeping files clean and efficient.
13+
- **Weighted Stability:** Stability and frequency scores are now updated
14+
proportionally using a weighted average of new evidence deltas against
15+
accumulated history.
16+
17+
### 🛠️ Interactive Model Management
18+
- **Model Selection & Validation:** Added an interactive step during `init` to
19+
specify custom models (e.g., `gemini-2.0-flash`) for 'rich' mode.
20+
- **Robust Validation:** Implemented automatic 60-second validation calls to
21+
verify model availability and connectivity before finalizing configuration.
22+
23+
### 📝 Professional Documentation Standards
24+
- **Architect-Level Prompts:** Completely redesigned LLM prompts for procedural
25+
and behavioral enrichment. The system now acts as a "Principal Engineer" or
26+
"Software Architect" to produce industry-standard documentation.
27+
- **Incremental Summarization:** LLM can now integrate new logs into existing
28+
manual rationales, building knowledge step-by-step.
29+
30+
### 🛡️ Core Stability
31+
- **Integrity Fix:** Resolved a critical `UnboundLocalError` in
32+
`IntegrityChecker` that affected incremental file updates.
33+
- **Test Suite Synchronization:** Updated all lifecycle tests to support the
34+
new cumulative logic and improved the specialized `lg.py` validator.
35+
36+
## What's Changed
37+
38+
- feat(core): implement fully cumulative lifecycle metrics model by @sl4m3
39+
- feat(cli): add interactive model selection and validation for rich mode by @sl4m3
40+
- feat(reasoning): upgrade LLM prompts to professional architect standards by @sl4m3
41+
- fix(core): resolve UnboundLocalError in IntegrityChecker by @sl4m3
42+
- fix(tests): synchronize lifecycle tests with incremental signal logic by @sl4m3
43+
44+
**Full changelog:** [v3.1.3...v3.2.0](https://github.com/sl4m3/ledgermind/compare/v3.1.3...v3.2.0)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "ledgermind"
7-
version = "3.1.3"
7+
version = "3.2.0"
88

99
description = "Monolithic Autonomous Agent Memory Management System"
1010
readme = "README.md"

src/ledgermind/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.1.3
1+
3.2.0

src/ledgermind/core/reasoning/lifecycle.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,46 +27,66 @@ def calculate_temporal_signals(
2727
now: datetime
2828
) -> DecisionStream:
2929
"""
30-
Updates temporal metrics: reinforcement_density, stability, coverage, lifetime_days.
30+
Updates temporal metrics incrementally based on a NEW delta of reinforcement_dates.
31+
This allows for clearing processed evidence IDs while maintaining accurate history.
3132
"""
3233
if not reinforcement_dates:
34+
# Still update lifetime metrics even with no new evidence
3335
stream.lifetime_days = (now - stream.first_seen).total_seconds() / 86400.0
34-
stream.reinforcement_density = 0.0
35-
stream.stability_score = 0.0
3636
stream.coverage = stream.lifetime_days / self.observation_window_days
3737
return stream
3838

3939
sorted_dates = sorted(reinforcement_dates)
40-
if stream.first_seen > sorted_dates[0]:
40+
41+
# 1. Update temporal boundaries
42+
if stream.frequency == 0:
43+
# Initial state: trust the new dates completely
4144
stream.first_seen = sorted_dates[0]
45+
stream.last_seen = sorted_dates[-1]
46+
else:
47+
# Incremental state: expand boundaries
48+
if stream.first_seen > sorted_dates[0]:
49+
stream.first_seen = sorted_dates[0]
4250

43-
stream.last_seen = sorted_dates[-1]
51+
if stream.last_seen < sorted_dates[-1]:
52+
stream.last_seen = sorted_dates[-1]
4453

4554
lifetime_secs = (stream.last_seen - stream.first_seen).total_seconds()
4655
stream.lifetime_days = lifetime_secs / 86400.0
47-
48-
# Avoid division by zero
4956
safe_lifetime = max(stream.lifetime_days, 0.01)
50-
51-
stream.frequency = len(sorted_dates)
57+
58+
# 2. Update Frequency (Cumulative)
59+
old_freq = stream.frequency
60+
delta_freq = len(sorted_dates)
61+
new_freq = old_freq + delta_freq
62+
stream.frequency = new_freq
63+
64+
# 3. Update Reinforcement Density
5265
stream.reinforcement_density = stream.frequency / safe_lifetime
5366

67+
# 4. Update Coverage
5468
stream.coverage = stream.lifetime_days / self.observation_window_days
5569

56-
if len(sorted_dates) > 2:
70+
# 5. Update Stability Score (Weighted Average)
71+
# Calculate stability for the NEW delta only
72+
delta_stability = 0.0
73+
if delta_freq > 2:
5774
intervals = [(sorted_dates[i] - sorted_dates[i-1]).total_seconds() / 86400.0
5875
for i in range(1, len(sorted_dates))]
5976
if len(intervals) > 1:
6077
var = statistics.variance(intervals)
61-
# Lower variance = higher stability. Use an inverse function or normalize.
62-
# Assuming variance of 0 is perfect stability (score 1.0).
63-
stream.stability_score = max(0.0, 1.0 - (var / (safe_lifetime + 1.0)))
64-
else:
65-
stream.stability_score = 0.0
66-
elif len(sorted_dates) == 2:
67-
stream.stability_score = 0.3 # Moderate stability signal for 2 events
78+
# Lower variance = higher stability
79+
delta_stability = max(0.0, 1.0 - (var / (safe_lifetime + 1.0)))
80+
elif delta_freq == 2:
81+
delta_stability = 0.3
82+
else:
83+
delta_stability = 0.0 # Single events don't provide stability signal
84+
85+
# Merge with existing stability using weighted average
86+
if old_freq > 0:
87+
stream.stability_score = (stream.stability_score * old_freq + delta_stability * delta_freq) / new_freq
6888
else:
69-
stream.stability_score = 0.0
89+
stream.stability_score = delta_stability
7090

7191
return stream
7292

src/ledgermind/core/reasoning/llm_enrichment.py

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ def process_batch(self, memory: Any):
102102
if status == "completed":
103103
updates = {
104104
"rationale": enriched.rationale,
105-
"enrichment_status": "completed"
105+
"enrichment_status": "completed",
106+
"evidence_event_ids": []
106107
}
107108

109+
if is_procedural:
110+
updates["procedural"] = None
111+
108112
with memory.semantic.transaction():
109113
memory.semantic.update_decision(
110114
filename=fid,
@@ -132,9 +136,9 @@ def enrich_proposal(self, proposal: Any, cluster_logs: Optional[str] = None) ->
132136
# Format input text for LLM
133137
if is_procedural:
134138
raw_text = self._format_procedural_text(proposal)
135-
prompt = self._build_procedural_prompt(raw_text)
139+
prompt = self._build_procedural_prompt(raw_text, existing_rationale=proposal.rationale)
136140
else:
137-
prompt = self._build_behavioral_prompt(proposal.target, cluster_logs)
141+
prompt = self._build_behavioral_prompt(proposal.target, cluster_logs, existing_rationale=proposal.rationale)
138142

139143
try:
140144
enriched_rationale = None
@@ -161,22 +165,91 @@ def _format_procedural_text(self, proposal: Any) -> str:
161165
text += f"Step {i+1}: {step.action}\nRationale: {step.rationale}\n\n"
162166
return text
163167

164-
def _build_procedural_prompt(self, raw_text: str) -> str:
168+
def _build_procedural_prompt(self, raw_text: str, existing_rationale: Optional[str] = None) -> str:
169+
context_part = ""
170+
if existing_rationale and "*Original Data:*" in existing_rationale:
171+
# Extract only the LLM-generated part
172+
clean_context = existing_rationale.split("*Original Data:*")[0].strip()
173+
if clean_context and "Overall Objective" in clean_context:
174+
context_part = (
175+
"EXISTING GUIDE CONTEXT:\n"
176+
"--------------------------\n"
177+
f"{clean_context}\n"
178+
"--------------------------\n\n"
179+
"The sequence below contains NEW execution steps that have occurred SINCE the existing guide was written.\n"
180+
)
181+
165182
return (
166-
"You are an expert AI architect summarizing system behavior.\n"
167-
"Analyze the following machine-generated execution logs and convert them "
168-
"into a single, coherent, human-readable summary of the actions taken and the rationale behind them. "
169-
"Focus on the 'why' and 'what'. Keep it concise but highly informative.\n\n"
170-
f"Logs:\n{raw_text}\n\nSummary:"
183+
"You are an expert Software Architect and Technical Documentation Specialist with 15+ years of experience. \n"
184+
"You excel at turning raw execution traces, command sequences, API calls, tool invocations, and successful action chains into clear, professional, human-readable procedural guides.\n\n"
185+
"TASK:\n"
186+
"Analyze the following procedural log/sequence of successful actions and transform it into a coherent, easy-to-follow step-by-step instruction guide for a developer or engineer.\n\n"
187+
f"{context_part}"
188+
"REQUIREMENTS:\n"
189+
"- Identify the overall purpose and final outcome.\n"
190+
"- Break everything into logical, numbered steps.\n"
191+
"- For each step clearly state:\n"
192+
" • WHAT is done\n"
193+
" • WHY it is done (technical or business reason)\n"
194+
"- Show dependencies and flow between steps.\n"
195+
"- Remove noise, abstract technical details where possible, but keep important parameters and outcomes.\n"
196+
"- Use concise, professional language.\n"
197+
"- IMPORTANT: If previous context is provided, INTEGRATE the new steps into the existing guide. Re-order, group, or refine the steps to maintain a logical and coherent flow. Update the 'Overall Objective' if needed.\n\n"
198+
"OUTPUT FORMAT (strictly follow this structure):\n\n"
199+
"1. **Overall Objective**\n"
200+
" One-sentence summary of what this procedure achieves.\n\n"
201+
"2. **Prerequisites** (if any)\n\n"
202+
"3. **Step-by-Step Procedure**\n"
203+
" 1. [Step description]\n"
204+
" • What: ...\n"
205+
" • Why: ...\n"
206+
" • Key details/parameters: ...\n\n"
207+
"4. **Key Insights & Recommendations**\n"
208+
" Any architectural observations, potential improvements, or best practices.\n\n"
209+
"Now analyze this sequence of NEW actions:\n\n"
210+
f"{raw_text}\n\nUpdated Procedural Guide:"
171211
)
172212

173-
def _build_behavioral_prompt(self, target: str, logs: str) -> str:
213+
def _build_behavioral_prompt(self, target: str, logs: str, existing_rationale: Optional[str] = None) -> str:
214+
context_part = ""
215+
if existing_rationale and "*Original Data:*" in existing_rationale:
216+
# Extract only the LLM-generated part, ignoring the raw data dump
217+
clean_context = existing_rationale.split("*Original Data:*")[0].strip()
218+
if clean_context and "Detected Technical Shift" in clean_context:
219+
context_part = (
220+
"PREVIOUS SUMMARY CONTEXT:\n"
221+
"--------------------------\n"
222+
f"{clean_context}\n"
223+
"--------------------------\n\n"
224+
"The logs below are NEW activities that have occurred SINCE the previous summary.\n"
225+
)
226+
174227
return (
175-
"You are an expert AI architect analyzing behavioral patterns in a codebase.\n"
176-
f"I have detected a high density of activity related to the component '{target}'.\n"
177-
"Based on the following execution logs, please provide a high-level summary of what the developer/agent "
178-
"has been working on in this area. Identify the main theme, goal, or technical shift reflected in these actions.\n\n"
179-
f"Logs:\n{logs[:5000]}\n\nSummary of Behavioral Pattern:"
228+
"You are a Principal Engineer and Codebase Archaeologist specializing in reverse-engineering developer intent from activity clusters.\n\n"
229+
"TASK:\n"
230+
"You are given a dense cluster of NEW events, logs, commits, or activities concentrated around a specific component, module, file, or target. \n"
231+
f"Analyze this high-density activity zone for '{target}' and extract the underlying technical shift, main goal, and behavioral pattern of the developer/team.\n\n"
232+
f"{context_part}"
233+
"REQUIREMENTS:\n"
234+
"- Identify the primary technical evolution or refactoring direction.\n"
235+
"- Uncover the core objective (what problem is being solved or opportunity pursued).\n"
236+
"- Detect recurring patterns in the work style or architectural decisions.\n"
237+
"- Base every conclusion on concrete evidence from the provided cluster.\n"
238+
"- IMPORTANT: If previous context is provided, INTEGRATE the new findings into a single, updated, and coherent summary. Refine the technical shift and goal if the new logs provide more clarity.\n\n"
239+
"OUTPUT FORMAT (strictly follow this structure):\n\n"
240+
"1. **Detected Technical Shift**\n"
241+
" One-sentence summary of the main change happening.\n\n"
242+
"2. **Primary Goal / Intent**\n"
243+
" What the developer is ultimately trying to achieve.\n\n"
244+
"3. **Key Patterns Observed**\n"
245+
" • Pattern 1: description + evidence\n"
246+
" • Pattern 2: ...\n\n"
247+
"4. **Architectural & Strategic Implications**\n"
248+
" How this activity affects the larger codebase and possible next steps or risks.\n\n"
249+
"5. **Component Evolution Summary**\n"
250+
" Brief before → after picture (if inferable).\n\n"
251+
"Now analyze this NEW activity cluster:\n\n"
252+
f"{logs[:5000]}\n\nUpdated Summary of Behavioral Pattern:"
180253
)
181254

182255
def _call_cli_model(self, prompt: str) -> Optional[str]:

src/ledgermind/core/reasoning/reflection.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import logging
32
import os
43
import json
@@ -173,8 +172,11 @@ def _process_stream(self, fid: str, data: Dict[str, Any], stats: Dict[str, Any],
173172
event_map = {e['id']: e for e in events}
174173

175174
reinforcement_dates = []
176-
all_evidence = set(stream.evidence_event_ids + stats['all_ids'])
177-
stream.evidence_event_ids = list(all_evidence)
175+
176+
# Update evidence list (queue for LLM enrichment)
177+
# Only add IDs that aren't already in the pending list
178+
new_ids = [eid for eid in stats['all_ids'] if eid not in stream.evidence_event_ids]
179+
stream.evidence_event_ids.extend(new_ids)
178180

179181
# Link procedural instructions if provided
180182
if procedural_links:
@@ -194,7 +196,8 @@ def _process_stream(self, fid: str, data: Dict[str, Any], stats: Dict[str, Any],
194196
# Define kinds that constitute a real 'use' or 'reinforcement' of knowledge (PR #30)
195197
REINFORCEMENT_KINDS = {KIND_RESULT, KIND_ERROR, "call", "task", "prompt", "intervention"}
196198

197-
for eid in stream.evidence_event_ids:
199+
# Extract dates ONLY for the NEW delta from the current cluster
200+
for eid in stats['all_ids']:
198201
if eid in event_map:
199202
ev = event_map[eid]
200203
if ev['kind'] in REINFORCEMENT_KINDS:
@@ -204,9 +207,7 @@ def _process_stream(self, fid: str, data: Dict[str, Any], stats: Dict[str, Any],
204207
except (ValueError, TypeError):
205208
pass
206209

207-
if not reinforcement_dates:
208-
reinforcement_dates = [now]
209-
210+
# calculate_temporal_signals now treats reinforcement_dates as a DELTA to be merged
210211
stream = self.lifecycle.calculate_temporal_signals(stream, reinforcement_dates, now)
211212

212213
# Issue #14: Reactivate dormant stream if new events arrived in this cluster
@@ -247,7 +248,7 @@ def _create_pattern_stream(self, target: str, stats: Dict[str, Any], now: dateti
247248
evidence_event_ids=stats['all_ids'],
248249
first_seen=now,
249250
last_seen=now,
250-
frequency=len(stats['all_ids'])
251+
frequency=0 # Will be updated by calculate_temporal_signals
251252
)
252253

253254
if arbitration_mode != "lite":
@@ -282,7 +283,7 @@ def _create_pattern_stream(self, target: str, stats: Dict[str, Any], now: dateti
282283
if not reinforcement_dates:
283284
reinforcement_dates = [now]
284285

285-
# Calculate initial temporal signals
286+
# Calculate initial temporal signals (cumulative)
286287
stream = self.lifecycle.calculate_temporal_signals(stream, reinforcement_dates, now)
287288
stream = self.lifecycle.promote_stream(stream)
288289

src/ledgermind/core/stores/semantic_store/integrity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ def validate(repo_path: str, force: bool = False, fid: str = None, data: Dict[st
5353
Supports incremental validation if fid is provided.
5454
'data' can be provided to avoid re-parsing the file.
5555
"""
56+
current_hash = IntegrityChecker._get_state_hash(repo_path)
5657
if not fid:
57-
current_hash = IntegrityChecker._get_state_hash(repo_path)
5858
if not force and IntegrityChecker._state_cache.get(repo_path) == current_hash:
5959
return
6060

0 commit comments

Comments
 (0)