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
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ Under Claude Code with the MeMesh plugin, hooks capture automatically:
- **Stop** captures session knowledge and turns failures into lessons.
- **PreCompact** saves important knowledge before history is compressed.
- **UserPromptSubmit** detects "remember this" intent in the prompt.
- **PreToolUse (Bash)** fires accepted lesson-guards: a fenced warning
citing the source lesson (`[mem:id]`) when a command matches a mistake
the graph has recorded. Heed it, and cite the lesson if it changes what
you do.

So under Claude Code: skip step 1 of the loop (the topology is already
injected), and do not `remember` commits or session summaries by hand. Manual
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,32 @@ All notable changes to MeMesh are documented here.

## [Unreleased]

### Added

- **Lesson guards: a recorded mistake can now warn at the moment it is
about to repeat.** The dreamer gained a guard stage: for each
failure-shaped lesson (the Error / Root cause / Fix structure) it
proposes a `{tool, pattern, message}` trigger — a regex over the Bash
command or the Edit/Write content about to run — and every proposal is
verified mechanically before staging: the pattern must compile, must
not match a benign-input probe list (`git status`, `npm test`, …), and
must pass its own attached evidence (at least two inputs that trigger,
two that stay silent — executed, not trusted). A human accepts or
rejects in the same review queue as every other proposal; acceptance
writes `metadata.guard` onto the source lesson (nothing is created or
archived, and the spec is re-verified with no model in the loop). At
runtime a new `guard-check` hook (PreToolUse Bash — MeMesh's seventh
hook) and the existing pre-edit-recall hook (Edit/Write, deliberately
outside its recall throttle: a dangerous edit is dangerous every time)
evaluate accepted guards as plain regex tests — no LLM, no network —
and a hit injects the lesson's warning as a fenced reference block
carrying the lesson's `[mem:id]` citation handle. v1 guards only WARN;
the schema carries `action` so per-guard blocking can arrive once
measured fire accuracy justifies it, and every fire is counted on the
guard (`fires`, `last_fired_at`) so a guard that never fires or fires
constantly surfaces for review. Guard failure of any kind degrades to
silence — the guard system can never block or break the user's work.

### Changed

- **Dashboard design system: VIVARIUM supersedes Precision Engineer.** The
Expand Down
3 changes: 2 additions & 1 deletion README.de.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ Reproduktionsbefehle, Datensatz-SHA256, rohe Ergebnisse pro Frage und Analyse be

## Was läuft in Claude Code automatisch ab

Sie müssen nicht manuell alles speichern. MeMesh verfügt über **6 Hooks**, die Wissen während der Arbeit erfassen und injizieren:
Sie müssen nicht manuell alles speichern. MeMesh verfügt über **7 Hooks**, die Wissen während der Arbeit erfassen und injizieren:

| Wenn | Was MeMesh tut |
|------|------------------|
Expand All @@ -351,6 +351,7 @@ Sie müssen nicht manuell alles speichern. MeMesh verfügt über **6 Hooks**, di
| **Nach jedem `git commit`** | Erfasst Ihre Änderungen mit Diff-Statistiken |
| **Wenn Claude stoppt** | Erfasst bearbeitete Dateien und behobene Fehler; generiert automatisch strukturierte Lektionen aus Fehlern |
| **Vor Context-Verdichtung** | Speichert Wissen, bevor es durch Context-Limits verloren geht |
| **Vor riskanten Befehlen und Edits** | Löst die von Ihnen akzeptierten Lektions-Guards aus — eine Warnung genau in dem Moment, in dem sich ein erfasster Fehler wiederholen würde |

> **Jederzeit abschalten:** `export MEMESH_AUTO_CAPTURE=false`

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ Re-runnable in ~10 seconds. Full instructions, dataset SHA256, raw per-question

## What Happens Automatically In Claude Code

You don't need to manually remember everything. MeMesh has **6 hooks** that capture and inject knowledge while you work:
You don't need to manually remember everything. MeMesh has **7 hooks** that capture and inject knowledge while you work:

| When | What MeMesh does |
|------|------------------|
Expand All @@ -364,6 +364,7 @@ You don't need to manually remember everything. MeMesh has **6 hooks** that capt
| **After every `git commit`** | Records what you changed, with diff stats |
| **When Claude stops** | Captures files edited, errors fixed, and auto-generates structured lessons from failures |
| **Before context compaction** | Saves knowledge before it's lost to context limits |
| **Before risky commands and edits** | Fires the lesson-guards you accepted — a warning at the exact moment a recorded mistake is about to repeat |

> **Opt out anytime:** `export MEMESH_AUTO_CAPTURE=false`

Expand Down
3 changes: 2 additions & 1 deletion README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ MeMesh 的檢索引擎**只用 FTS5**(熱路徑上不使用 LLM、不使用嵌

## Claude Code 自動進行的事情

你不需要手動記住所有事情。MeMesh 有 **6 個 hooks**,會在你工作時自動擷取與注入知識:
你不需要手動記住所有事情。MeMesh 有 **7 個 hooks**,會在你工作時自動擷取與注入知識:

| 何時 | MeMesh 做什麼 |
|------|------------------|
Expand All @@ -360,6 +360,7 @@ MeMesh 的檢索引擎**只用 FTS5**(熱路徑上不使用 LLM、不使用嵌
| **每次 `git commit` 之後** | 記錄你的變更,包含 diff 統計 |
| **Claude 停止時** | 擷取已編輯的檔案、已修復的錯誤,並從失敗自動產生結構化教訓 |
| **上下文壓縮前** | 在知識被上下文限制丟掉之前先保存 |
| **危險指令與編輯前** | 觸發你接受過的教訓守衛——在記錄過的錯誤即將重演的那一刻發出警告 |

> **隨時退出:** `export MEMESH_AUTO_CAPTURE=false`

Expand Down
8 changes: 4 additions & 4 deletions dashboard/dist/index.html

Large diffs are not rendered by default.

49 changes: 48 additions & 1 deletion dashboard/src/components/InsightsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,54 @@ export function InsightsTab() {
);
})()}

{detail && detail.proposed_digest && p.kind !== 'relation' && (
{/* Guard proposals (G1) carry a GuardSpec payload — the reviewer
is approving a regex that will warn on future tool inputs, so
the card shows the pattern, the message it will speak, and the
evidence examples the validator executed. */}
{detail && detail.proposed_digest && p.kind === 'guard' && (() => {
const g = detail.proposed_digest as unknown as {
guard?: { tool?: string; pattern?: string; message?: string; should_match?: string[]; should_not_match?: string[] };
source_lesson?: { name?: string; title?: string | null };
};
return (
<div style={{ marginTop: 12, padding: 12, background: 'var(--bg-1)', borderRadius: 'var(--radius-xs)', fontSize: 13 }}>
<div style={{ marginBottom: 8, color: 'var(--text-3)', fontSize: 11 }}>
{t('insights.generatedBy')}: <code>{detail.llm_model ?? t('common.unknown')}</code> · {t('insights.promptVersion')}: <code>{detail.prompt_version}</code>
</div>
<div style={{ marginBottom: 8 }}>
<span class="tag" style={{ fontSize: 11 }}>{g.guard?.tool}</span>
<span style={{ marginLeft: 8, color: 'var(--text-3)', fontSize: 11 }}>{t('guard.sourceLesson')}:</span>{' '}
<span style={{ fontSize: 12 }}>{g.source_lesson?.title || g.source_lesson?.name}</span>
</div>
<div style={{ marginBottom: 8 }}>
<div style={{ fontSize: 11, color: 'var(--text-3)', marginBottom: 2 }}>{t('guard.pattern')}</div>
<code style={{ fontFamily: 'var(--mono)', fontSize: 12, wordBreak: 'break-all' }}>{g.guard?.pattern}</code>
</div>
<div style={{ marginBottom: 8 }}>
<div style={{ fontSize: 11, color: 'var(--text-3)', marginBottom: 2 }}>{t('guard.message')}</div>
<div style={{ lineHeight: 1.5 }}>{g.guard?.message}</div>
</div>
{(g.guard?.should_match?.length || g.guard?.should_not_match?.length) ? (
<div style={{ fontSize: 12, color: 'var(--text-2)' }}>
{g.guard?.should_match?.length ? (
<div style={{ marginBottom: 4 }}>
<span style={{ color: 'var(--text-3)', fontSize: 11 }}>{t('guard.shouldMatch')}:</span>{' '}
{g.guard.should_match.map((ex, i) => <code key={i} style={{ fontFamily: 'var(--mono)', fontSize: 11, marginRight: 8 }}>{ex}</code>)}
</div>
) : null}
{g.guard?.should_not_match?.length ? (
<div>
<span style={{ color: 'var(--text-3)', fontSize: 11 }}>{t('guard.shouldNotMatch')}:</span>{' '}
{g.guard.should_not_match.map((ex, i) => <code key={i} style={{ fontFamily: 'var(--mono)', fontSize: 11, marginRight: 8 }}>{ex}</code>)}
</div>
) : null}
</div>
) : null}
</div>
);
})()}

{detail && detail.proposed_digest && p.kind !== 'relation' && p.kind !== 'guard' && (
<div style={{ marginTop: 12, padding: 12, background: 'var(--bg-1)', borderRadius: 'var(--radius-xs)', fontSize: 13 }}>
<div style={{ marginBottom: 8, color: 'var(--text-3)', fontSize: 11 }}>
{t('insights.generatedBy')}: <code>{detail.llm_model ?? t('common.unknown')}</code> · {t('insights.promptVersion')}: <code>{detail.prompt_version}</code>
Expand Down
Loading
Loading