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 @@ -8,7 +8,7 @@
"name": "memesh",
"source": "./",
"description": "MeMesh \u2014 local collaboration for AI coding agents. Share memory across sessions, exchange task messages, and preserve work context. One SQLite file; no cloud required.",
"version": "4.10.11",
"version": "4.10.12",
"author": {
"name": "PCIRCLE AI"
},
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": {
"name": "PCIRCLE AI"
},
"version": "4.10.11",
"version": "4.10.12",
"mcpServers": "./.claude-plugin/mcp.json",
"homepage": "https://github.com/PCIRCLE-AI/memesh",
"repository": "https://github.com/PCIRCLE-AI/memesh",
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "memesh",
"description": "MeMesh — local collaboration for AI coding agents. Share memory across sessions and exchange task messages.",
"version": "4.10.11",
"version": "4.10.12",
"mcpServers": "./.codex-plugin/mcp.json"
}
11 changes: 3 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ jobs:
run: bash scripts/release-verify.sh --skip-suite

# `node scripts/verify.mjs --journeys` runs the journey steps of
# `npm run verify` — build, the packaged smoke, the dashboard e2e — and
# `npm run verify` — build and the packaged smoke — and
# logs the git tree hash it verified. verify:release and the suite are not
# repeated here: every Build & Test leg runs them, one on this OS and Node.
#
Expand All @@ -320,10 +320,8 @@ jobs:
# receipt for a different tree is a finding. The test step before it keeps
# scripts/verify.mjs and scripts/verify-receipt.mjs honest about themselves.
#
# This is the only job that runs the packaged dashboard e2e on a pull
# request. A separate job used to run the same command on the same OS and
# Node; tests/release-scripts-safety.test.ts pins that this job runs the
# journeys and that the packaged and e2e steps are still marked as journeys.
# Dashboard UI verification is skipped for this release. The existing
# journey runner still verifies the build and installed package.
sdlc-verify:
name: SDLC verify
runs-on: ubuntu-latest
Expand Down Expand Up @@ -353,9 +351,6 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Install Playwright Chromium
run: npx playwright install --with-deps chromium

- name: Verify module tests (tree hash, receipt, verify runner)
run: node --test scripts/verify.test.mjs scripts/lib/verify-core.test.mjs

Expand Down
7 changes: 2 additions & 5 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,13 @@ jobs:
# the release gate exists to prevent.

- name: Run tests
# vitest.config.ts skips release UI tests; shared API/data tests remain required.
run: npm test -- --run

- name: Smoke test packaged artifact
run: npm run test:packaged

- name: Install Playwright Chromium
run: npx playwright install --with-deps chromium

- name: Smoke test packaged dashboard
run: npm run test:e2e-dashboard
# SKIP: Dashboard UI functional tests are waived for this release.

- name: Source verification (`npm run verify:release`)
# The same gates ci.yml runs on every PR. This workflow had neither, so
Expand Down
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,52 @@ All notable changes to MeMesh are documented here.

## [Unreleased]

## [4.10.12] — 2026-10-09

### Changed

- HTTP `forget` now returns 404 for a missing memory and 400 for a non-matching observation instead of a successful 200 no-op. Clients that relied on the old response must handle the error path; successful removals, archives and repeat archives remain successful (#596).

- A decision now keeps the reason it was made. `remember` takes `why` (CLI `--why`): the reason for the decision and what would make it stop holding. It is stored as the observation `Why: …`; a reason typed with its own `Why: ` label is stored with one label. Creating a memory of type `decision`, `architecture_decision` or `design_decision` without it — or rewriting one with `replace` — is refused, with a message that names both halves; adding to an existing decision does not need it, and a note file or an `import` is still stored (untrusted, so it appears in the briefing only once trusted), as is an accepted dream proposal. Before, a decision could be stored as a bare conclusion, and the briefing showed only its title, so a later session could not tell whether the reason behind it still applied. The CLI's `fix it with:` command after a quick-form decision now carries `--why`, so copying it is not refused.
- The briefing, the session-start block and the durable-memory index (`briefing --index`, `GET /v1/briefing-index`) show each decision with its latest `Why:` after the title, or `(no reason recorded)` when it has none, and a decision that nobody has recalled or added to for 30 days with `(unconfirmed N days: re-check before relying)`. Recalling it clears that note. The age counts the newest observation of every decision type, not only `decision`, so `architecture_decision` and `design_decision` are marked too. When a decision line is cut to its budget, the title is clipped first (down to 40 characters), then the reason, and the notes and the `[mem:id]` handle are never cut; a decision whose first observation is a reason shows only its latest reason, once. A read or observation dated in the future is ignored, and a decision with no observation is aged from its creation in the ranked block as in the index.
- The Hermes and OpenClaw extensions pass `why` through. Hermes returns the server's own sentence when a write is refused, as OpenClaw's `memory_store` does, instead of a bare status line; both say `why` is required for `decision`, `architecture_decision` and `design_decision`. The decision-nudge and "remember this" hooks tell the agent a decision needs `why`, and the documentation's `remember` examples for a decision carry one.

### Fixed

- Stop capture no longer records failed or unanswered file-edit requests as completed work. Successful edit results are stored as neutral observations rather than claims that errors were fixed; normal session handoffs remain available.

- A session handoff replaced by another local host records its latest writer instead of retaining the first host's label. Briefing and SessionStart name a known Claude Code or Codex source; legacy handoffs with no reliable source retain their existing heading (#515).

- CLI command failures keep exit code 1 and the error message without a Node stack trace. Message validation failures name the invalid field instead of dumping schema JSON; `message watch` keeps its JSONL error shape.
- `install-hooks` and `uninstall-hooks` reject an invalid `--scope` before touching settings instead of treating it as `user`.

- Task-state updates read and merge while holding the database write lock, so concurrent updates to different fields preserve both values and their stated dates. Unchanged fields and no-op writes keep their existing dates and history.

- MCP update notices are suppressed only after a hook actually emitted its notice. Pending, failed or invalid prompt claims no longer hide an available update when a hook stops before announcing it.

- Signal-score, accepted-proposal trust and title backfills take the write lock before reading their work list. Failed passes roll back, report pending completion and defer retry for 24 hours while startup continues; lock contention retries on the next start. Existing JSON completion records and populated fields remain intact.

- Update checks and legacy caches accept npm's JSON-string version output and reject empty or invalid versions. A failed check keeps its previous valid result and deprecation signal, but does not claim the installed version is current; CLI and hook notices use the same version validation.

- File attribution reports unreadable Git blame history as unknown, rather than claiming a valid line is out of range. Confirmed range errors and uncommitted lines keep their existing reasons.
- Explicit per-session Upgrade approval is checked at Stop even on short turns or when memory capture is disabled. Fresh target and exact session/version/channel checks remain required; unattended update settings are unchanged.
- The bundled CLI can refresh a missing or stale update cache without a SessionStart hook. A failed background start reports unknown status, releases its refresh claim and leaves the calling CLI or MCP process usable.
- Background CLI/MCP cache refresh checks registry versions without opening or migrating the memory database, so it cannot contend with the caller's graph operation.
- Legacy malformed metadata no longer aborts fused-lesson shell repair or the read-only invariant audit; malformed rows remain intact.
- Briefing reserves section headings before selecting complete rows, and commit explanations exclude archived commit entities.
- A failed data repair reports that its transaction rolled back and the repair remains pending, without prescribing an unrelated search-index rebuild. Search-index failures retain the `memesh reindex --fts` retry instruction.
- A lesson recalled before editing now shows its newest fix and its memory handle; lesson names and text remain redacted. Ordinary memory selection and project isolation remain unchanged (#602).
- A read-only `VACUUM INTO` backup opens for reads through both the CLI/core and hooks without changing the file or granting write access. Switching its journal mode no longer prevents opening the backup; other database errors still propagate.
- Task state keeps a separate stated date for each field: a new goal no longer makes old done, next or blocked text look fresh in briefing or SessionStart. The CLI and Dashboard show each field date; untouched values stay stored and an empty string still clears a field (#406).
- Forgotten task state is hidden from reads and startup briefings. Stating a new field starts fresh instead of reviving archived goal or completion fields.
- A non-record JSON line such as `null` no longer aborts transcript work-package preparation; visible conversation before and after the line remains eligible.
- Generated task-state titles respect the shared 200-character limit without shortening the stored field. Title and task-field truncation no longer split an emoji at the boundary.
- Clearing an empty field on unreadable task-state metadata reports a failure instead of claiming a successful no-change. The recovery message directs callers to set a non-empty field; rejected clears leave the original record intact.
- SessionStart reports unreadable task-state metadata with the same recovery hint as briefing, while retaining the project's other memories. Archived state remains excluded.
- Legacy task-state headings use the same strict timestamp and clock-skew rules as briefing: invalid dates remain unknown, and an accepted near-future timestamp reads as today. Stored fields and the 72-hour freshness threshold remain unchanged.

- Restoring a backup through MCP or HTTP keeps archived memories archived, retains creation times and restores permitted metadata, as the CLI does. Malformed restore fields are refused before the entry is written (#594).

- The dashboard's Project page loads the selected project's memories a page at a time ("Load older memories") instead of the newest 2000 of the whole library, so a project whose memories are older than that no longer reads as empty while its chip counts them. `GET /v1/entities` takes `project` — decided by the rule `GET /v1/projects` counts with (the `project:` tag, else a `lesson-<project>-<pattern>` name of a project at least two characters long; the project's session handoff is not one of its memories) — and `offset`; the Memories filter chips use the same rule. Switching project no longer shows the previous project's memories if the new project's first page fails to load, "Load older memories" keeps keyboard focus while it loads, and the notice beside it counts the memories the list shows.
- Dashboard Home: a rate-limited server no longer tells you to reload and run `memesh doctor`; the next-step card no longer claims to have checked the search index, and shows "unavailable" instead of "checking" forever when the server's health request fails; the memory-loop percentage compares the last seven days with the seven days before them (it compared the last seven days that had activity); the timeline chart fills its card, clears when the data is removed and spaces its bars by day; an empty library no longer scores a health of 0; and accepting a compaction proposal says how many source memories it archived.
- `npm run audit:memory` reports a memory whose `replaced_history` is not a list, holds more than 50 versions or is larger than 256 KiB, and exits 2 when a file is not a database or cannot be queried, instead of printing a clean verdict.
Expand Down
2 changes: 1 addition & 1 deletion CODEMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# CODEMAP

**Version**: 4.10.11
**Version**: 4.10.12

A navigation map for the codebase: *"I want to change X — which file?"* For the
design rationale behind these modules see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md);
Expand Down
17 changes: 17 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ Documentation is part of the change, not follow-up work. CI's version, generated

## Cutting a Release

An explicit release-owner decision may reuse valid baseline evidence plus
affected deltas, or mark Dashboard review `SKIP`. Record that decision privately
in `.qa/release-evidence-reuse.json`; never commit it or rewrite an old failed
receipt as a passing run. The mapping names `version`, the clean candidate's
`revision` and `tree`, `authority.decidedBy` and `authority.decision`, `uiSkip`,
the `g6` applicability rationale, separate `hosts.codex` and `hosts.claude`
rationales, and retained `concerns`. Its `evidence` entries each carry `scope`
(`g6`, `codex`, or `claude`), `path`, `sha256`, and the source-to-candidate
`mapping`. Both hosts and G6 require source entries; changed or missing sources
are rejected. Without this explicit mapping, the normal checks below apply.

Approved reuse is printed as `REUSED_WITH_CONCERNS`, never as a fresh native or
full-suite PASS. Build, source/security/version checks, packed-candidate smoke,
memory audit, main/clean-tree/remote/tag checks and publication channels remain
required. A failed native report for the same candidate cannot be hidden by
reuse. UI omission is printed as `SKIP`, not PASS.

A release is one operation, not three commands:

```bash
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ MeMesh lets agents share memory and exchange messages locally. Its main uses are
- **Capture, recall, reminders, and safeguards at the right time.** MeMesh ships **10 hooks** (ten hook commands) across its Claude Code and Codex integrations: nine Claude Code hooks run at session start, before file edits, after `git commit`, after a plan is approved or a question answered, when Claude stops (twice: capturing session knowledge, and blocking the stop once per waiting agent message), before context compaction, when you say "remember this" (5 languages), and before a risky command that repeats an accepted lesson. The plan/question and "remember this" hooks only remind the agent to call `remember`; the tenth command handles both Codex SessionStart and SessionEnd to register and retire an eligible ordinary Codex CLI session.
- **One memory for all your tools.** A decision stored from Claude Code is available to Codex or Cursor the next day.
- **Agents can leave each other messages.** A durable inbox survives restarts; on macOS or Linux, an ordinary Codex CLI thread with the MeMesh plugin can keep a bounded post-turn native queue window and consume the accepted message when that same thread resumes.
- **Keep a work handoff.** Claude Code can save its latest substantive reply for the next session in the same project. Use `task_state` to record a stated goal, next step, blocker, or completion, and `message` to send evidence locations or follow-up questions to an exact recipient.
- **Keep a work handoff.** Claude Code can save its latest substantive reply for the next session in the same project. The briefing names a known Claude Code or Codex handoff source, so another host's reply is distinguishable; replacing a handoff updates its writer. Use `task_state` to record a stated goal, next step, blocker, or completion, and `message` to send evidence locations or follow-up questions to an exact recipient.
- **A dashboard** to browse it all: 4 tabs, 11 languages, at `http://localhost:3737/dashboard`.

---
Expand Down
2 changes: 1 addition & 1 deletion README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ MeMesh 讓代理在本機共用記憶與交換訊息。主要用途是跨 sessio
- **在適當時機記錄、提醒與防護。** MeMesh 的 Claude Code 與 Codex 整合共提供 **10 個 hook command**:其中 9 個 Claude Code hook 分別在開新對話、改檔案前、`git commit` 後、計畫核准或你回答問題後、Claude 停下來時(兩次:記錄這次對話內容,以及在還有訊息未讀時擋下結束)、對話被壓縮前、你說「記下來」時(聽得懂 5 種語言),以及執行可能重犯已接受教訓的危險指令前運作。計畫/問題與「記下來」hook 只會提醒 agent 呼叫 `remember`;第 10 個 command 同時處理 Codex SessionStart 與 SessionEnd,註冊並退場符合資格的一般 Codex CLI session。
- **所有工具共用一份記憶。** 今天在 Claude Code 存的決定,明天 Codex 或 Cursor 也用得到。
- **agent 之間可以留言。** 本機的耐久收件匣可跨重啟保存;在 macOS 或 Linux 上,裝有 MeMesh plugin 的一般 Codex CLI thread 可保留有界的回合後原生 queue 視窗,並在同一 thread 恢復時取用已被接受的訊息。
- **留下工作交接。** Claude Code 可把最後一則有實質內容的回覆留給同一專案的下個 session。用 `task_state` 記錄已明確說出的目標、下一步、阻礙或完成項目,再用 `message` 將證據位置或待處理問題送給確切收件者。
- **留下工作交接。** Claude Code 可把最後一則有實質內容的回覆留給同一專案的下個 session。Briefing 會標示已知的 Claude Code 或 Codex 交接來源,讓另一個 host 的回覆可被辨識;取代交接時也會更新作者來源。用 `task_state` 記錄已明確說出的目標、下一步、阻礙或完成項目,再用 `message` 將證據位置或待處理問題送給確切收件者。
- **有儀表板** 可以瀏覽全部內容:4 個分頁、11 種語言,在 `http://localhost:3737/dashboard`。

---
Expand Down
22 changes: 11 additions & 11 deletions dashboard/dist/index.html

Large diffs are not rendered by default.

Loading
Loading