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
12 changes: 10 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Version 2 - MARM Protocol to Universal MCP Server Evolution

<details>
<summary><strong>Unreleased: SQLite Write Atomicity Hardening (v2.22.x)</strong></summary>
<summary><strong>Unreleased: SQLite Write Atomicity Hardening (v2.22.1)</strong></summary>

### Multi-Statement Writes Are Now Real Transactions

Expand All @@ -13,6 +13,14 @@
- Every new transaction boundary has a mutation-tested regression test (`tests/test_sqlite_write_atomicity.py`): each one forces a specific SQL statement to fail and asserts the earlier statement(s) in the same block did not durably apply — a happy-path-only test doesn't prove rollback. Coverage now also includes the session-switch, dated-fallback, targeted log-delete, and notebook-delete transaction boundaries.
- No schema changes, no new endpoints, no tool-surface changes. Pure reliability hardening.

### MARM Console Memory Tab Reaches Dashboard Parity

- Filled the remaining Memory workspace gaps from the legacy `marm-dashboard`: Console can now create sessions, delete one session, delete all sessions, delete individual log rows, bulk-delete logs, add/delete notebook entries, and stage/apply/discard compaction candidates from the same Memory tab surface.
- The new Console routes call existing MARM MCP tool paths for mutations instead of writing directly to SQLite, preserving the queue-backed memory write rules and transport behavior while the old dashboard remains available for reference.
- Added visible success/error feedback for session, log, notebook, and compaction actions so failed queue/MCP operations no longer disappear silently in the UI.
- Notebook add/delete now preserves optional `project`/`platform` scope across Console and the existing MCP tool paths, so same-name notebook entries in different scopes are not collapsed by UI mutations.
- Added FastAPI response-contract tests for the new Console Memory routes with the MCP adapter stubbed, matching the rule that every new Console API route gets at least one real response-layer test.

</details>

<details>
Expand All @@ -30,7 +38,7 @@
</details>

<details>
<summary><strong>Unreleased: Log-Entry Cross-Transport Dedup (v2.21.3)</strong></summary>
<summary><strong>July 15th, 2026: Log-Entry Cross-Transport Dedup (v2.21.3)</strong></summary>

### Shared Log-Entry Logic

Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
width="900"
height="250">
</picture>
<h1 align="center">MARM: Local-First Persistent Multi-Agent Memory Layer for MCP Clients v2.22.0</h1>
<h1 align="center">MARM: Local-First Persistent Multi-Agent Memory Layer for MCP Clients v2.22.1</h1>

[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/Lyellr88/marm-memory/blob/MARM-main/LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
Expand All @@ -24,7 +24,11 @@

</div>

## Important Message - marm-console has been added but it is not fully active yet coming soon!
## Important Messages

- marm-console now ships as the local web app successor to marm-dashboard, with live Memory, Knowledge, and Projects workspaces plus MCP-backed Memory mutation actions. Packaging and one-command startup polish are still in progress.
- I am waiting to get access back to my PYPI account, till restored pip will be behind a few versions. I will update the README when it is back up to date.
Comment thread
coderabbitai[bot] marked this conversation as resolved.


## Table of Contents

Expand Down Expand Up @@ -550,9 +554,9 @@ The AI agent will automatically use the appropriate tools. Manual tool access is
| `marm_smart_recall` | Hybrid recall: exact lane for config keys, commands, and file paths; semantic rerank for natural-language queries | `query`, `limit`, `session_name`, `search_all`, `detail=1/2/3`, `project`, `platform`, `exact_mode` |
| `marm_log_entry` | Add structured session log entries; each entry is also embedded into semantic memory so `marm_smart_recall` can find it | `entry`, `session_name` |
| `marm_log_show` | Display all entries and sessions, with filtering | `session_name` |
| `marm_delete` | Delete a log session, log entry, or notebook entry | `type`, `target`, `session_name` |
| `marm_delete` | Delete a log session, log entry, or notebook entry | `type`, `target`, `session_name`, `project`, `platform` |
| `marm_summary` | Cached, paste-ready session summaries with intelligent truncation | `session_name` |
| `marm_notebook` | Reusable instructions and knowledge snippets | `action="add"\|"use"\|"show"\|"status"\|"clear"`, `name`, `data` |
| `marm_notebook` | Reusable instructions and knowledge snippets | `action="add"\|"use"\|"show"\|"status"\|"clear"`, `name`, `data`, `project`, `platform` |
| `marm_compaction` | Agent-assisted memory cleanup with a reviewable audit trail | `action="status"\|"candidates"\|"review"\|"stage"\|"apply"\|"discard"` |

### 🕸️ Code Graph (5 tools)
Expand Down
2 changes: 1 addition & 1 deletion docs/INSTALL-DOCKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Universal Memory Intelligence Platform for AI Agents

**MARM v2.22.0** - Memory Accurate Response Mode
**MARM v2.22.1** - Memory Accurate Response Mode
*Docker deployment guide for Windows, Mac, and Linux*

---
Expand Down
4 changes: 2 additions & 2 deletions docs/INSTALL-LINUX.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Universal Memory Intelligence Platform for AI Agents

**MARM v2.22.0** - Memory Accurate Response Mode
**MARM v2.22.1** - Memory Accurate Response Mode
*Complete Linux installation guide*

---
Expand Down Expand Up @@ -320,7 +320,7 @@ curl -s http://localhost:8001/health
{
"status": "healthy",
"service": "MARM MCP Server",
"version": "2.22.0",
"version": "2.22.1",
"timestamp": "2026-01-01T00:00:00+00:00",
"database": "connected",
"semantic_search": "available"
Expand Down
2 changes: 1 addition & 1 deletion docs/INSTALL-PLATFORMS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MARM v2.22.0 MCP Server - Platform Integration Guide
# MARM v2.22.1 MCP Server - Platform Integration Guide

## Table of Contents

Expand Down
4 changes: 2 additions & 2 deletions docs/INSTALL-WINDOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Universal Memory Intelligence Platform for AI Agents

**MARM v2.22.0** - Memory Accurate Response Mode
**MARM v2.22.1** - Memory Accurate Response Mode
*Complete Windows installation guide*

---
Expand Down Expand Up @@ -293,7 +293,7 @@ Invoke-WebRequest -Uri http://localhost:8001/health
{
"status": "healthy",
"service": "MARM MCP Server",
"version": "2.22.0",
"version": "2.22.1",
"timestamp": "2026-01-01T00:00:00+00:00",
"database": "connected",
"semantic_search": "available"
Expand Down
73 changes: 73 additions & 0 deletions marm-console/artifacts/marm-console/src/hooks/use-marm-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,84 @@ export function useSessions() {
return useQuery({ queryKey: queryKeys.sessions(baseUrl), queryFn: client.listSessions });
}

export function useCreateSession() {
const { baseUrl, client } = useMarmConfig();
const qc = useQueryClient();
return useMutation({
mutationFn: (name: string) => client.createSession(name),
onSuccess: () => {
qc.invalidateQueries({ queryKey: queryKeys.sessions(baseUrl) });
qc.invalidateQueries({ queryKey: queryKeys.filters(baseUrl) });
qc.invalidateQueries({ queryKey: queryKeys.overview(baseUrl) });
},
});
}

export function useDeleteSession() {
const { baseUrl, client } = useMarmConfig();
const qc = useQueryClient();
const invalidate = () => {
qc.invalidateQueries({ queryKey: queryKeys.sessions(baseUrl) });
qc.invalidateQueries({ queryKey: ['logs', baseUrl] });
qc.invalidateQueries({ queryKey: ['memories', baseUrl] });
qc.invalidateQueries({ queryKey: queryKeys.filters(baseUrl) });
qc.invalidateQueries({ queryKey: queryKeys.overview(baseUrl) });
};
return useMutation({
mutationFn: (name: string) => client.deleteSession(name),
onSuccess: invalidate,
});
}

export function useDeleteAllSessions() {
const { baseUrl, client } = useMarmConfig();
const qc = useQueryClient();
return useMutation({
mutationFn: () => client.deleteAllSessions(),
onSuccess: () => {
qc.invalidateQueries({ queryKey: queryKeys.sessions(baseUrl) });
qc.invalidateQueries({ queryKey: ['logs', baseUrl] });
qc.invalidateQueries({ queryKey: ['memories', baseUrl] });
qc.invalidateQueries({ queryKey: queryKeys.filters(baseUrl) });
qc.invalidateQueries({ queryKey: queryKeys.overview(baseUrl) });
},
});
}

export function useLogs(params?: LogListParams) {
const { baseUrl, client } = useMarmConfig();
return useQuery({ queryKey: queryKeys.logs(baseUrl, params), queryFn: () => client.listLogs(params) });
}

export function useDeleteLog() {
const { baseUrl, client } = useMarmConfig();
const qc = useQueryClient();
const invalidate = () => {
qc.invalidateQueries({ queryKey: ['logs', baseUrl] });
qc.invalidateQueries({ queryKey: ['memories', baseUrl] });
qc.invalidateQueries({ queryKey: queryKeys.sessions(baseUrl) });
qc.invalidateQueries({ queryKey: queryKeys.overview(baseUrl) });
};
return useMutation({
mutationFn: ({ id, sessionName }: { id: number; sessionName: string }) => client.deleteLog(id, sessionName),
onSuccess: invalidate,
});
}

export function useDeleteAllLogs() {
const { baseUrl, client } = useMarmConfig();
const qc = useQueryClient();
return useMutation({
mutationFn: () => client.deleteAllLogs(),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['logs', baseUrl] });
qc.invalidateQueries({ queryKey: ['memories', baseUrl] });
qc.invalidateQueries({ queryKey: queryKeys.sessions(baseUrl) });
qc.invalidateQueries({ queryKey: queryKeys.overview(baseUrl) });
},
});
}

export function useSummary(session: string) {
const { baseUrl, client } = useMarmConfig();
return useQuery({ queryKey: queryKeys.summary(baseUrl, session), queryFn: () => client.getSummary(session), enabled: !!session });
Expand Down
40 changes: 39 additions & 1 deletion marm-console/artifacts/marm-console/src/lib/marm-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,52 @@ export function createMarmClient(config: MarmClientConfig) {

// Sessions / logs / notebook / summary
listSessions: () => request<Session[]>(config, 'GET', '/sessions'),
createSession: (name: string) =>
request<{ name: string; active: boolean; status: string }>(config, 'POST', '/sessions', { body: { name } }),
deleteSession: (name: string) =>
request<{ session_name: string; deleted_count: number; memories_deleted: number }>(
config,
'DELETE',
`/sessions/${encodeURIComponent(name)}`,
{ body: { confirm: 'DELETE' } },
),
deleteAllSessions: () =>
request<{
status: string;
deleted_sessions: number;
deleted_count: number;
memories_deleted: number;
failed_sessions: Array<{ session_name: string; status_code: number; message: string }>;
}>(
config,
'DELETE',
'/sessions',
{ body: { confirm: 'DELETE_ALL' } },
),
listLogs: (params?: LogListParams) =>
request<LogEntry[]>(config, 'GET', '/logs', { query: params }),
deleteLog: (id: number, sessionName: string) =>
request<{ log_id: string; session_name: string; deleted_count: number; memories_deleted: number }>(
config,
'DELETE',
`/logs/${encodeURIComponent(String(id))}`,
{ body: { session_name: sessionName, confirm: 'DELETE' } },
),
deleteAllLogs: () =>
request<{ deleted_count: number; memories_deleted: number }>(
config,
'DELETE',
'/logs',
{ body: { confirm: 'DELETE_ALL' } },
),
listNotebook: (params?: { q?: string; project?: string; platform?: string }) =>
request<NotebookEntry[]>(config, 'GET', '/notebook', { query: params }),
upsertNotebook: (data: NotebookInput) =>
request<NotebookEntry>(config, 'POST', '/notebook', { body: data }),
deleteNotebookEntry: (name: string, params?: { project?: string; platform?: string }) =>
request<void>(config, 'DELETE', `/notebook/${encodeURIComponent(name)}`, { query: params }),
request<{ name: string; deleted: boolean }>(config, 'DELETE', `/notebook/${encodeURIComponent(name)}`, {
body: { confirm: 'DELETE', project: params?.project, platform: params?.platform },
}),
getSummary: (session: string) =>
request<SessionSummary>(config, 'GET', `/summaries/${encodeURIComponent(session)}`),

Expand Down
Loading
Loading