@lh8ppl/claude-memory-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cmk-compress-lazy.mjs +59 -0
- package/bin/cmk-daily-distill.mjs +67 -0
- package/bin/cmk-weekly-curate.mjs +56 -0
- package/bin/cmk.mjs +12 -0
- package/package.json +50 -0
- package/src/audit-log.mjs +103 -0
- package/src/auto-extract.mjs +742 -0
- package/src/capture-prompt.mjs +61 -0
- package/src/capture-turn.mjs +273 -0
- package/src/claude-md.mjs +212 -0
- package/src/compress-session.mjs +349 -0
- package/src/compressor.mjs +376 -0
- package/src/conflict-queue.mjs +796 -0
- package/src/cooldown.mjs +61 -0
- package/src/daily-distill.mjs +252 -0
- package/src/doctor.mjs +528 -0
- package/src/forget.mjs +335 -0
- package/src/frontmatter.mjs +73 -0
- package/src/import-anthropic-memory.mjs +266 -0
- package/src/index-db.mjs +154 -0
- package/src/index-rebuild.mjs +597 -0
- package/src/index.mjs +90 -0
- package/src/inject-context.mjs +484 -0
- package/src/install.mjs +327 -0
- package/src/lazy-compress.mjs +326 -0
- package/src/lock-discipline.mjs +166 -0
- package/src/mcp-server.mjs +498 -0
- package/src/memory-write.mjs +565 -0
- package/src/merge-facts.mjs +213 -0
- package/src/observe-edit.mjs +87 -0
- package/src/platform-commands.mjs +138 -0
- package/src/poison-guard.mjs +245 -0
- package/src/privacy.mjs +21 -0
- package/src/provenance.mjs +217 -0
- package/src/register-crons.mjs +354 -0
- package/src/reindex.mjs +134 -0
- package/src/repair.mjs +316 -0
- package/src/result-shapes.mjs +155 -0
- package/src/review-queue.mjs +345 -0
- package/src/roll.mjs +115 -0
- package/src/scratchpad.mjs +335 -0
- package/src/search.mjs +311 -0
- package/src/subcommands.mjs +1252 -0
- package/src/tier-paths.mjs +74 -0
- package/src/transcripts.mjs +234 -0
- package/src/trust.mjs +226 -0
- package/src/weekly-curate.mjs +454 -0
- package/src/write-fact.mjs +205 -0
- package/template/.claude/hooks/pre-tool-memory.js +78 -0
- package/template/.claude/hooks/transcript-capture.js +69 -0
- package/template/.claude/settings.json +27 -0
- package/template/.claude/skills/memory-write/SKILL.md +117 -0
- package/template/.gitignore.fragment +12 -0
- package/template/CLAUDE.md.template +49 -0
- package/template/docs/journey/journey-log.md.template +292 -0
- package/template/local/machine-paths.md.template +37 -0
- package/template/local/overrides.md.template +36 -0
- package/template/project/.index/.gitkeep +0 -0
- package/template/project/MEMORY.md.template +47 -0
- package/template/project/SOUL.md.template +35 -0
- package/template/project/memory/INDEX.md.template +47 -0
- package/template/project/memory/archive/superseded/.gitkeep +0 -0
- package/template/project/memory/archive/tombstones/.gitkeep +0 -0
- package/template/project/queues/.gitkeep +0 -0
- package/template/project/sessions/.gitkeep +0 -0
- package/template/project/transcripts/.gitkeep +0 -0
- package/template/support/cron-jobs/daily-memory-distill.md +15 -0
- package/template/support/cron-jobs/nightly-memsearch-index.md +17 -0
- package/template/support/cron-jobs/weekly-memory-curator.md +15 -0
- package/template/support/milvus-deploy/README.md +57 -0
- package/template/support/milvus-deploy/docker-compose.yml +66 -0
- package/template/support/scripts/auto-extract-memory.sh +102 -0
- package/template/support/scripts/memsearch-index-with-flush.sh +59 -0
- package/template/support/scripts/refresh-distill-timestamp.py +35 -0
- package/template/support/scripts/register-crons.py +242 -0
- package/template/support/scripts/run-daily-distill.sh +67 -0
- package/template/support/scripts/run-weekly-curate.sh +58 -0
- package/template/user/HABITS.md.template +18 -0
- package/template/user/LESSONS.md.template +18 -0
- package/template/user/USER.md.template +18 -0
- package/template/user/fragments/INDEX.md.template +23 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!-- Cap: 1500 chars · Last distilled: {{TODAY}} · Last health check: {{TODAY}} -->
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
overrides.md = machine-specific overrides of preferences declared elsewhere.
|
|
5
|
+
Local tier (gitignored). Highest precedence in the 3-tier model.
|
|
6
|
+
3 fixed sections per design §2.1.
|
|
7
|
+
|
|
8
|
+
Bullet+provenance format (universal — see provenance.mjs):
|
|
9
|
+
- (L-XXXXXXXX) the bullet text on one line
|
|
10
|
+
<!-- source, source_line, sha1, write, trust, at -->
|
|
11
|
+
|
|
12
|
+
Auto-populated by `cmk persona generate` (Task N, design §16.16); empty is fine.
|
|
13
|
+
-->
|
|
14
|
+
|
|
15
|
+
# Machine-specific overrides (local tier)
|
|
16
|
+
|
|
17
|
+
## Tool Overrides
|
|
18
|
+
|
|
19
|
+
<!-- Editor/shell/tool overrides for this machine. -->
|
|
20
|
+
|
|
21
|
+
- (L-AUT6CX47) (example) editor: code --wait
|
|
22
|
+
<!-- source: overrides.md, source_line: 20, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
23
|
+
|
|
24
|
+
## Behavior Overrides
|
|
25
|
+
|
|
26
|
+
<!-- Behavior changes for this machine (offline mode, rate limits, etc.). -->
|
|
27
|
+
|
|
28
|
+
- (L-2QZJRZLT) (example) offline mode: true
|
|
29
|
+
<!-- source: overrides.md, source_line: 27, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
30
|
+
|
|
31
|
+
## Path Overrides
|
|
32
|
+
|
|
33
|
+
<!-- Path overrides for this machine. -->
|
|
34
|
+
|
|
35
|
+
- (L-YRDULPLW) (example) workspace root: ~/Projects
|
|
36
|
+
<!-- source: overrides.md, source_line: 34, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!-- Cap: 2500 chars · Last distilled: {{TODAY}} · Last health check: {{TODAY}} -->
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
MEMORY.md is the working scratchpad. Cap measured by `wc -c` over the whole
|
|
5
|
+
file (header + comments + bullets). Consolidation triggers at >95% (Task 12);
|
|
6
|
+
stale bullets (>14d without `trust: high`) drop on consolidate. Three fixed
|
|
7
|
+
sections per design §2.1.
|
|
8
|
+
|
|
9
|
+
Bullet+provenance format (universal across all scratchpads):
|
|
10
|
+
- (P-XXXXXXXX) the bullet text on one line
|
|
11
|
+
<!-- source: <file>, source_line: <int>, sha1: <40-hex>, write: <enum>, trust: <enum>, at: <ISO 8601> -->
|
|
12
|
+
|
|
13
|
+
Each section ships with a placeholder seed bullet — replace with real project
|
|
14
|
+
state. Empty sections are fine if you haven't captured anything yet.
|
|
15
|
+
-->
|
|
16
|
+
|
|
17
|
+
# Working Memory
|
|
18
|
+
|
|
19
|
+
## Active Threads
|
|
20
|
+
|
|
21
|
+
<!--
|
|
22
|
+
Current work in progress. Drop bullets when work resolves. Auto-extract
|
|
23
|
+
(Task 23) writes here; manual edits welcome too.
|
|
24
|
+
-->
|
|
25
|
+
|
|
26
|
+
- (P-T6M95JXF) (example) reviewing PR #142 for the auth refactor
|
|
27
|
+
<!-- source: MEMORY.md, source_line: 22, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
28
|
+
|
|
29
|
+
## Environment Notes
|
|
30
|
+
|
|
31
|
+
<!--
|
|
32
|
+
Tool versions, paths, URLs, env state. Update on change. Auto-extract picks
|
|
33
|
+
these up from PostToolUse hook events; manual edits welcome.
|
|
34
|
+
-->
|
|
35
|
+
|
|
36
|
+
- (P-R662a95Y) (example) Node 20.x; Python 3.13; Postgres 16 in the test environment
|
|
37
|
+
<!-- source: MEMORY.md, source_line: 30, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
38
|
+
|
|
39
|
+
## Pending Decisions
|
|
40
|
+
|
|
41
|
+
<!--
|
|
42
|
+
Things the user still has to decide. Remove when resolved. Auto-populated by
|
|
43
|
+
`cmk persona generate` (Task N, design §16.16); empty is fine.
|
|
44
|
+
-->
|
|
45
|
+
|
|
46
|
+
- (P-KU3aNBX9) (example) decide whether to deprecate /api/v1 by Q3 2026
|
|
47
|
+
<!-- source: MEMORY.md, source_line: 38, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!-- Cap: 1800 chars · Last distilled: {{TODAY}} · Last health check: {{TODAY}} -->
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
SOUL.md = project persona / disposition / norms. Where USER.md = "who the user
|
|
5
|
+
is", SOUL.md = "how Claude should show up". 3 fixed sections per design §2.1.
|
|
6
|
+
|
|
7
|
+
Bullet+provenance format (universal — see provenance.mjs):
|
|
8
|
+
- (P-XXXXXXXX) the bullet text on one line
|
|
9
|
+
<!-- source, source_line, sha1, write, trust, at -->
|
|
10
|
+
|
|
11
|
+
Auto-populated by `cmk persona generate` (Task N, design §16.16); empty is fine.
|
|
12
|
+
-->
|
|
13
|
+
|
|
14
|
+
# Project Soul
|
|
15
|
+
|
|
16
|
+
## Tone and Disposition
|
|
17
|
+
|
|
18
|
+
<!-- How Claude communicates in this project. -->
|
|
19
|
+
|
|
20
|
+
- (P-9Ba72DB2) explains tradeoffs before recommending; doesn't lead with conclusions
|
|
21
|
+
<!-- source: SOUL.md, source_line: 18, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
22
|
+
|
|
23
|
+
## Operating Defaults
|
|
24
|
+
|
|
25
|
+
<!-- Standing rules for how Claude works. -->
|
|
26
|
+
|
|
27
|
+
- (P-PCD975WA) verifies external claims against primary sources before stating as fact
|
|
28
|
+
<!-- source: SOUL.md, source_line: 25, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
29
|
+
|
|
30
|
+
## Boundary Rules
|
|
31
|
+
|
|
32
|
+
<!-- What Claude must NOT do. -->
|
|
33
|
+
|
|
34
|
+
- (P-U5ELYUZQ) writes to memory silently; doesn't announce captures
|
|
35
|
+
<!-- source: SOUL.md, source_line: 32, sha1: 0000000000000000000000000000000000000000, write: manual-edit, trust: medium, at: 2020-01-01T00:00:00Z -->
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Granular Memory Archive — Index
|
|
2
|
+
|
|
3
|
+
This file lists every per-fact memory file in `context/memory/`. **NOT auto-loaded at session start** — read this index when looking up whether a topic has a saved memory.
|
|
4
|
+
|
|
5
|
+
## Purpose vs. the bounded scratchpad
|
|
6
|
+
|
|
7
|
+
| File | Purpose | Loaded at startup? | Cap |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `../MEMORY.md` | Hot working state (current threads, environment, pending decisions) | Yes | 2,500 chars |
|
|
10
|
+
| `../USER.md` | User profile and preferences | Yes | 1,375 chars |
|
|
11
|
+
| `./<type>_<slug>.md` (this dir) | Durable typed facts with reasoning | No | none |
|
|
12
|
+
|
|
13
|
+
## When to write where
|
|
14
|
+
|
|
15
|
+
- **Durable typed fact** (user role, project decision with rationale, feedback rule, external system pointer) → new file here, plus one-line entry below.
|
|
16
|
+
- **Working state** (current threads, today's environment notes, open decisions) → `../MEMORY.md`.
|
|
17
|
+
- If a fact graduates from working state to durable archive, MOVE it (don't duplicate).
|
|
18
|
+
|
|
19
|
+
## Frontmatter format for granular files
|
|
20
|
+
|
|
21
|
+
````markdown
|
|
22
|
+
---
|
|
23
|
+
name: short-kebab-case-slug
|
|
24
|
+
description: one-line summary used for retrieval
|
|
25
|
+
metadata:
|
|
26
|
+
type: user | feedback | project | reference
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
[Body. For feedback / project entries, lead with the rule or fact, then:
|
|
30
|
+
**Why:** the reason / context / past incident
|
|
31
|
+
**How to apply:** when this guidance kicks in, edge cases to watch]
|
|
32
|
+
|
|
33
|
+
Link related entries with [[their-slug]].
|
|
34
|
+
````
|
|
35
|
+
|
|
36
|
+
## Type taxonomy
|
|
37
|
+
|
|
38
|
+
- `user_*.md` — facts about the user (role, goals, knowledge, responsibilities).
|
|
39
|
+
- `feedback_*.md` — corrections or confirmations about how to approach work. Always include Why + How to apply.
|
|
40
|
+
- `project_*.md` — facts about ongoing initiatives or decisions specific to a project. Time-bound.
|
|
41
|
+
- `reference_*.md` — pointers to external systems (Linear, Slack, dashboards, repos).
|
|
42
|
+
|
|
43
|
+
## Files
|
|
44
|
+
|
|
45
|
+
<!-- (No granular files yet. As you accumulate, add one line per file:
|
|
46
|
+
- [type] [Title](filename.md) — short hook
|
|
47
|
+
-->
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Daily Memory Distillation
|
|
3
|
+
time: '23:00'
|
|
4
|
+
days: daily
|
|
5
|
+
active: 'true'
|
|
6
|
+
description: 'Distills durable facts from today''s session log into MEMORY.md and updates Last-distilled timestamp'
|
|
7
|
+
timeout: 10m
|
|
8
|
+
job_type: shell_command
|
|
9
|
+
command: 'bash scripts/run-daily-distill.sh'
|
|
10
|
+
working_directory: '${CLAUDE_PROJECT_DIR}'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Invokes Claude headlessly to extract durable facts from `context/sessions/{today}.md` into `context/MEMORY.md`. Promotes typed facts to `context/memory/<type>_*.md` granular files. Enforces the 2,500-char MEMORY.md cap by consolidating older entries if needed. Updates the `Last distilled` timestamp so HC-3 stays green.
|
|
14
|
+
|
|
15
|
+
See `scripts/run-daily-distill.sh` for the exact prompt and tool allowlist.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Nightly MemSearch Index
|
|
3
|
+
time: '02:00'
|
|
4
|
+
days: daily
|
|
5
|
+
active: 'true'
|
|
6
|
+
description: 'Re-indexes context/ markdown files for vector search'
|
|
7
|
+
timeout: 10m
|
|
8
|
+
job_type: shell_command
|
|
9
|
+
command: 'bash scripts/memsearch-index-with-flush.sh context/memory context/sessions context/transcripts'
|
|
10
|
+
working_directory: '${CLAUDE_PROJECT_DIR}'
|
|
11
|
+
# Requires Layer 5 installed (memsearch on PATH + a reachable Milvus backend).
|
|
12
|
+
# On Windows: Docker Desktop running with Milvus container — see context/SETUP.md.
|
|
13
|
+
# If memsearch isn't installed or backend isn't reachable, the task will fail;
|
|
14
|
+
# HC-7 (backend reachability) will flag it on the next session start.
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
Updates the memsearch vector index with any new content from `context/memory/`, `context/sessions/`, and `context/transcripts/`. Idempotent: only re-embeds chunks whose hash changed since the last run.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Weekly Memory Curator
|
|
3
|
+
time: '09:00'
|
|
4
|
+
days: sun
|
|
5
|
+
active: 'true'
|
|
6
|
+
description: 'Prunes, merges, and consolidates entries in MEMORY.md; updates Last-health-check timestamp'
|
|
7
|
+
timeout: 15m
|
|
8
|
+
job_type: shell_command
|
|
9
|
+
command: 'bash scripts/run-weekly-curate.sh'
|
|
10
|
+
working_directory: '${CLAUDE_PROJECT_DIR}'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Conservative cleanup pass on `context/MEMORY.md`. Removes resolved Active Threads, merges duplicate bullets, drops clearly stale entries — but never ADDS content (that's the daily-distill's job). Logs results to today's session log under a "## Session — automated curation" heading.
|
|
14
|
+
|
|
15
|
+
See `scripts/run-weekly-curate.sh` for the exact prompt and tool allowlist.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Milvus deployment (Windows + optional)
|
|
2
|
+
|
|
3
|
+
This compose stack runs Milvus v2.6.16 plus its required dependencies (etcd, MinIO) as three local containers. It's used by **Layer 5** (memsearch vector search) of the memory system.
|
|
4
|
+
|
|
5
|
+
## When you need this
|
|
6
|
+
|
|
7
|
+
- **Windows**: required. `milvus-lite` (the default embedded vector store memsearch ships) has no Windows wheels on PyPI. Use this Docker stack instead.
|
|
8
|
+
- **Linux / macOS**: optional. memsearch auto-installs milvus-lite and uses it at `~/.memsearch/milvus.db`. Skip this directory entirely unless you specifically want a remote Milvus.
|
|
9
|
+
|
|
10
|
+
## Bring it up
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cd milvus-deploy
|
|
14
|
+
docker compose up -d
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Wait ~30-60 seconds for all three containers to report `(healthy)`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
docker compose ps
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
You should see `milvus-etcd`, `milvus-minio`, `milvus-standalone` all `Up (healthy)`.
|
|
24
|
+
|
|
25
|
+
## Configure memsearch to use it
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
memsearch config set milvus.uri "http://localhost:19530"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Bring it down
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
docker compose down
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Volumes persist in `./volumes/` — re-running `up -d` reuses the same data.
|
|
38
|
+
|
|
39
|
+
## Why a multi-container stack and not just `milvus-standalone`?
|
|
40
|
+
|
|
41
|
+
Milvus standalone needs etcd (metadata store) and MinIO (object storage for segments and index data). On Linux/macOS, `milvus-lite` bundles all of that into one Python wheel; on Windows there's no equivalent wheel, so the three services run as separate containers.
|
|
42
|
+
|
|
43
|
+
The single-container `docker run milvusdb/milvus:latest standalone` pattern referenced in some older docs is no longer supported — `latest` is `v3.0-beta` whose entrypoint doesn't accept `standalone` as a command. Use this compose file with the pinned versions instead.
|
|
44
|
+
|
|
45
|
+
## Known quirk: memsearch index without flush
|
|
46
|
+
|
|
47
|
+
memsearch v0.4.x doesn't call `flush()` after `MilvusStore.upsert()`. On Milvus v2.6+ (Woodpecker WAL), this means `memsearch index` reports success but the data isn't searchable until a flush forces the growing segment to seal.
|
|
48
|
+
|
|
49
|
+
Use `scripts/memsearch-index-with-flush.sh` instead of raw `memsearch index` until upstream ships a fix. Tracked as [memsearch issue #534](https://github.com/zilliztech/memsearch/issues/534).
|
|
50
|
+
|
|
51
|
+
## Pinned versions
|
|
52
|
+
|
|
53
|
+
| Image | Version | Why pinned |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `milvusdb/milvus` | `v2.6.16` | Latest stable v2.6 line. `latest` tag is v3.0-beta and crashes. |
|
|
56
|
+
| `quay.io/coreos/etcd` | `v3.5.25` | Compatible with milvus v2.6. |
|
|
57
|
+
| `minio/minio` | `RELEASE.2024-12-18T13-15-44Z` | Recent stable RELEASE tag. |
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
version: '3.5'
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
etcd:
|
|
5
|
+
container_name: milvus-etcd
|
|
6
|
+
image: quay.io/coreos/etcd:v3.5.25
|
|
7
|
+
environment:
|
|
8
|
+
- ETCD_AUTO_COMPACTION_MODE=revision
|
|
9
|
+
- ETCD_AUTO_COMPACTION_RETENTION=1000
|
|
10
|
+
- ETCD_QUOTA_BACKEND_BYTES=4294967296
|
|
11
|
+
- ETCD_SNAPSHOT_COUNT=50000
|
|
12
|
+
volumes:
|
|
13
|
+
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
|
|
14
|
+
command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
|
|
15
|
+
healthcheck:
|
|
16
|
+
test: ["CMD", "etcdctl", "endpoint", "health"]
|
|
17
|
+
interval: 30s
|
|
18
|
+
timeout: 20s
|
|
19
|
+
retries: 3
|
|
20
|
+
|
|
21
|
+
minio:
|
|
22
|
+
container_name: milvus-minio
|
|
23
|
+
image: minio/minio:RELEASE.2024-12-18T13-15-44Z
|
|
24
|
+
environment:
|
|
25
|
+
MINIO_ACCESS_KEY: minioadmin
|
|
26
|
+
MINIO_SECRET_KEY: minioadmin
|
|
27
|
+
ports:
|
|
28
|
+
- "9001:9001"
|
|
29
|
+
- "9000:9000"
|
|
30
|
+
volumes:
|
|
31
|
+
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
|
|
32
|
+
command: minio server /minio_data --console-address ":9001"
|
|
33
|
+
healthcheck:
|
|
34
|
+
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
|
35
|
+
interval: 30s
|
|
36
|
+
timeout: 20s
|
|
37
|
+
retries: 3
|
|
38
|
+
|
|
39
|
+
standalone:
|
|
40
|
+
container_name: milvus-standalone
|
|
41
|
+
image: milvusdb/milvus:v2.6.16
|
|
42
|
+
command: ["milvus", "run", "standalone"]
|
|
43
|
+
security_opt:
|
|
44
|
+
- seccomp:unconfined
|
|
45
|
+
environment:
|
|
46
|
+
ETCD_ENDPOINTS: etcd:2379
|
|
47
|
+
MINIO_ADDRESS: minio:9000
|
|
48
|
+
MQ_TYPE: woodpecker
|
|
49
|
+
volumes:
|
|
50
|
+
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
|
|
51
|
+
healthcheck:
|
|
52
|
+
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
|
|
53
|
+
interval: 30s
|
|
54
|
+
start_period: 90s
|
|
55
|
+
timeout: 20s
|
|
56
|
+
retries: 3
|
|
57
|
+
ports:
|
|
58
|
+
- "19530:19530"
|
|
59
|
+
- "9091:9091"
|
|
60
|
+
depends_on:
|
|
61
|
+
- "etcd"
|
|
62
|
+
- "minio"
|
|
63
|
+
|
|
64
|
+
networks:
|
|
65
|
+
default:
|
|
66
|
+
name: milvus
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Auto-extract: invoked by the Stop hook in the background after every
|
|
4
|
+
# assistant turn. Reads the turn from a temp file, runs Claude headlessly
|
|
5
|
+
# with a focused fact-extraction prompt, and lets Claude write any
|
|
6
|
+
# durable facts to MEMORY.md / USER.md / granular archive via the
|
|
7
|
+
# memory-write skill.
|
|
8
|
+
#
|
|
9
|
+
# This is the "make it automatic" piece: instead of the user having to
|
|
10
|
+
# say "remember this", the system harvests memory-worthy content from
|
|
11
|
+
# every turn on its own.
|
|
12
|
+
#
|
|
13
|
+
# Args:
|
|
14
|
+
# $1 — path to a temp file containing the assistant turn's text
|
|
15
|
+
#
|
|
16
|
+
# Detached from the parent hook — runs in background, fire-and-forget.
|
|
17
|
+
# Errors are swallowed (logged to context/sessions/{today}.extract.log).
|
|
18
|
+
|
|
19
|
+
# Detached process contexts don't always inherit Git Bash's PATH on
|
|
20
|
+
# Windows. Set it up explicitly. On Linux/macOS this is a no-op since
|
|
21
|
+
# /usr/bin is already present.
|
|
22
|
+
case ":$PATH:" in
|
|
23
|
+
*":/usr/bin:"*) ;;
|
|
24
|
+
*) export PATH="/usr/bin:/c/Program Files/Git/usr/bin:$PATH" ;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
27
|
+
set -u
|
|
28
|
+
|
|
29
|
+
TURN_FILE="${1:-}"
|
|
30
|
+
[ -z "$TURN_FILE" ] && exit 0
|
|
31
|
+
[ ! -f "$TURN_FILE" ] && exit 0
|
|
32
|
+
|
|
33
|
+
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
34
|
+
cd "$REPO_ROOT"
|
|
35
|
+
|
|
36
|
+
TODAY=$(date +%Y-%m-%d)
|
|
37
|
+
LOG="${REPO_ROOT}/context/sessions/${TODAY}.extract.log"
|
|
38
|
+
|
|
39
|
+
TURN_TEXT=$(cat "$TURN_FILE")
|
|
40
|
+
|
|
41
|
+
trap "rm -f \"$TURN_FILE\"" EXIT
|
|
42
|
+
|
|
43
|
+
# Skip very short turns — nothing to extract.
|
|
44
|
+
TURN_LEN=${#TURN_TEXT}
|
|
45
|
+
if [ "$TURN_LEN" -lt 100 ]; then
|
|
46
|
+
echo "[$(date -Iseconds)] skip: turn too short ($TURN_LEN chars)" >> "$LOG"
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
PROMPT=$(cat <<EOF
|
|
51
|
+
You are running as a silent background auto-extract task for this project. No one is watching this output. Be CONSERVATIVE — only capture what is clearly durable. Most turns will have nothing to save. That is the correct outcome.
|
|
52
|
+
|
|
53
|
+
GOAL: look at the assistant turn below and decide whether the user (in the conversation that produced it) said anything that should be saved to memory. If yes, write it to context/MEMORY.md, context/USER.md, or context/memory/<type>_<slug>.md using the memory-write skill.
|
|
54
|
+
|
|
55
|
+
EXTRACT and SAVE only when one of these is clearly present:
|
|
56
|
+
- User explicitly asked to remember ("remember this", "note that", "save this", "from now on", "going forward", "i prefer")
|
|
57
|
+
- User made a concrete decision worth carrying forward ("we're using X not Y", "let's go with X")
|
|
58
|
+
- User corrected the assistant ("actually it's X not Y", "you got that wrong, X is the right answer")
|
|
59
|
+
- Assistant acknowledged a NEW environment fact not already in MEMORY.md / USER.md (new tool version, new path, new config)
|
|
60
|
+
- Assistant identified a durable rule with "Why:" / "How to apply:" structure
|
|
61
|
+
|
|
62
|
+
DO NOT save:
|
|
63
|
+
- Conversational chatter, hello/goodbye
|
|
64
|
+
- One-off task execution narration ("ran the script, got output X")
|
|
65
|
+
- Information already in MEMORY.md / USER.md / context/memory/ (check INDEX.md)
|
|
66
|
+
- Anything you would summarize as "we discussed X" without a concrete decision
|
|
67
|
+
|
|
68
|
+
STEPS:
|
|
69
|
+
1. Read context/MEMORY.md, context/USER.md, and context/memory/INDEX.md to know current state.
|
|
70
|
+
2. Read the turn content (passed as the user message of this conversation).
|
|
71
|
+
3. If anything durable is present, use the memory-write skill rules:
|
|
72
|
+
- Choose the right file (scratchpad vs USER.md vs granular archive)
|
|
73
|
+
- Dedup-check against existing content
|
|
74
|
+
- Cap-check (consolidate first if over)
|
|
75
|
+
- Write a single bullet, concise (<200 chars)
|
|
76
|
+
4. If nothing durable: exit silently. Do not write.
|
|
77
|
+
5. Output ONE line of plain text: either "saved: <one-line summary of what>" or "skip: nothing durable" — for the log.
|
|
78
|
+
|
|
79
|
+
CONSTRAINTS:
|
|
80
|
+
- Use Read, Edit, and Bash(wc *) only.
|
|
81
|
+
- Do NOT create new files outside context/memory/.
|
|
82
|
+
- Do NOT commit, push, or run git operations.
|
|
83
|
+
- Do NOT print anything except the one-line outcome.
|
|
84
|
+
|
|
85
|
+
=== TURN CONTENT ===
|
|
86
|
+
${TURN_TEXT}
|
|
87
|
+
=== END TURN ===
|
|
88
|
+
EOF
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
mkdir -p "$(dirname "$LOG")"
|
|
92
|
+
echo "[$(date -Iseconds)] auto-extract fired on turn len=$TURN_LEN" >> "$LOG"
|
|
93
|
+
|
|
94
|
+
OUTPUT=$(echo "$PROMPT" | claude --print \
|
|
95
|
+
--add-dir "$REPO_ROOT" \
|
|
96
|
+
--allowed-tools "Read" "Edit" "Bash(wc *)" \
|
|
97
|
+
--output-format text \
|
|
98
|
+
2>&1)
|
|
99
|
+
EXIT=$?
|
|
100
|
+
|
|
101
|
+
echo "[$(date -Iseconds)] auto-extract exit=$EXIT output: $OUTPUT" >> "$LOG"
|
|
102
|
+
exit 0
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Wraps `memsearch index` to also force a Milvus flush afterward.
|
|
4
|
+
#
|
|
5
|
+
# Why: Milvus v2.6+ uses the Woodpecker WAL backend, which (unlike v2.5's
|
|
6
|
+
# Pulsar) does not auto-flush growing segments on a short timer. As a result,
|
|
7
|
+
# `memsearch index` reports "Indexed N chunks" successfully but
|
|
8
|
+
# `get_collection_stats` returns 0 rows and search returns no results until
|
|
9
|
+
# a manual flush forces the growing segment to seal.
|
|
10
|
+
#
|
|
11
|
+
# This wrapper runs the index, then issues a flush via pymilvus.
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# bash scripts/memsearch-index-with-flush.sh context/memory context/sessions context/transcripts
|
|
15
|
+
#
|
|
16
|
+
# Reads MILVUS_URI from env (falls back to the memsearch config value, then localhost).
|
|
17
|
+
# Reads MILVUS_COLLECTION from env (falls back to memsearch config, then "memsearch_chunks").
|
|
18
|
+
|
|
19
|
+
# Task Scheduler / launchd / unattended cron contexts don't always inherit
|
|
20
|
+
# the user's PATH. Set it up explicitly for the common locations.
|
|
21
|
+
case ":$PATH:" in
|
|
22
|
+
*":/usr/bin:"*) ;;
|
|
23
|
+
*) export PATH="/usr/bin:/usr/local/bin:/opt/homebrew/bin:/c/Program Files/Git/usr/bin:$PATH" ;;
|
|
24
|
+
esac
|
|
25
|
+
|
|
26
|
+
# On Windows, also add the Python Scripts dir where `memsearch.exe` lands.
|
|
27
|
+
if [ -d "/c/Users/$USERNAME/AppData/Local/Programs/Python" ]; then
|
|
28
|
+
for d in /c/Users/$USERNAME/AppData/Local/Programs/Python/Python*/Scripts \
|
|
29
|
+
/c/Users/$USERNAME/AppData/Local/Programs/Python/Python*; do
|
|
30
|
+
[ -d "$d" ] && export PATH="$d:$PATH"
|
|
31
|
+
done
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
set -euo pipefail
|
|
35
|
+
|
|
36
|
+
# Step 1 — index. Pass through all args.
|
|
37
|
+
memsearch index "$@"
|
|
38
|
+
|
|
39
|
+
# Step 2 — flush.
|
|
40
|
+
MILVUS_URI="${MILVUS_URI:-$(memsearch config get milvus.uri 2>/dev/null | tail -n1 | tr -d '\r')}"
|
|
41
|
+
MILVUS_COLLECTION="${MILVUS_COLLECTION:-$(memsearch config get milvus.collection 2>/dev/null | tail -n1 | tr -d '\r')}"
|
|
42
|
+
MILVUS_URI="${MILVUS_URI:-http://localhost:19530}"
|
|
43
|
+
MILVUS_COLLECTION="${MILVUS_COLLECTION:-memsearch_chunks}"
|
|
44
|
+
|
|
45
|
+
# Flush only if we're using a remote Milvus (milvus-lite auto-flushes).
|
|
46
|
+
case "$MILVUS_URI" in
|
|
47
|
+
http://*|https://*|tcp://*)
|
|
48
|
+
python -c "
|
|
49
|
+
from pymilvus import MilvusClient
|
|
50
|
+
client = MilvusClient(uri='${MILVUS_URI}')
|
|
51
|
+
client.flush('${MILVUS_COLLECTION}')
|
|
52
|
+
stats = client.get_collection_stats('${MILVUS_COLLECTION}')
|
|
53
|
+
print(f'Flushed. Collection {stats!r}')
|
|
54
|
+
"
|
|
55
|
+
;;
|
|
56
|
+
*)
|
|
57
|
+
echo "Local milvus-lite detected (${MILVUS_URI}); skipping flush (auto-flush)."
|
|
58
|
+
;;
|
|
59
|
+
esac
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Tiny helper for the daily-memory-distill cron job.
|
|
4
|
+
|
|
5
|
+
Rewrites the `<!-- Last distilled: YYYY-MM-DD -->` line in
|
|
6
|
+
context/MEMORY.md to today's date. Keeps HC-3 green even when the real
|
|
7
|
+
distillation (Claude-driven extraction of facts from sessions/) isn't
|
|
8
|
+
wired up yet.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python scripts/refresh-distill-timestamp.py
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import datetime
|
|
16
|
+
import re
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
21
|
+
MEMORY = REPO_ROOT / "context" / "MEMORY.md"
|
|
22
|
+
|
|
23
|
+
if not MEMORY.exists():
|
|
24
|
+
print(f"ERROR: {MEMORY} not found", file=sys.stderr)
|
|
25
|
+
sys.exit(1)
|
|
26
|
+
|
|
27
|
+
today = datetime.date.today().isoformat()
|
|
28
|
+
text = MEMORY.read_text(encoding="utf-8")
|
|
29
|
+
new_text, n = re.subn(r"Last distilled: \d{4}-\d{2}-\d{2}",
|
|
30
|
+
f"Last distilled: {today}", text, count=1)
|
|
31
|
+
if n == 0:
|
|
32
|
+
print("WARN: no 'Last distilled:' line found in MEMORY.md; nothing to update", file=sys.stderr)
|
|
33
|
+
sys.exit(0)
|
|
34
|
+
MEMORY.write_text(new_text, encoding="utf-8")
|
|
35
|
+
print(f"OK: updated Last distilled to {today}")
|