Skip to content

Commit 34bc35c

Browse files
Paul Kyleclaude
andcommitted
scrub: clean migration files, update stale numbers for launch
- migration/mem0_export: configurable collections via env var, remove hardcoded clawd/attractor/governor/gradient references - migration/mem0_classify: generic entity examples, generic paths - migration/mem0_generate: generic paths - migration/run_mem0_backfill: generic path in log message - CHANGELOG: VRAM -> memory budget - ADR-001: 17 -> 18 MCP tools - LAUNCH-POSTS-FINAL: 56 -> 92 tests, 17 -> 18 tools, updated HN post to final version Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f84259b commit 34bc35c

File tree

7 files changed

+34
-35
lines changed

7 files changed

+34
-35
lines changed

ADR-001-tools-over-pipeline.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
## Decision
88

9-
Palinode's primary value is its **17 MCP tools + file-based storage + git versioning**, not its 4-phase injection pipeline. The pipeline is scaffolding for current models. The tools survive any model upgrade.
9+
Palinode's primary value is its **18 MCP tools + file-based storage + git versioning**, not its 4-phase injection pipeline. The pipeline is scaffolding for current models. The tools survive any model upgrade.
1010

1111
## Context
1212

docs/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- Commands: search, save, status, diff, consolidate, trigger, doctor
88
- TTY-aware output (human text vs piped JSON)
99
- Remote access via `PALINODE_API` env var or SSH
10-
- **GPU usage plane spec**VRAM budget for embeddings + transcription + general LLM
10+
- **GPU usage plane spec**memory budget for embeddings + transcription + general LLM
1111
- **Architecture decision: CLI vs MCP** — CLI for agents/scripts/cron (8x fewer tokens), MCP for IDEs only
1212
- Updated README architecture diagram to show CLI path
1313
- Updated ROADMAP with Phase 1.25 (CLI + interface rationalization)

docs/LAUNCH-POSTS-FINAL.md

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Reply to: https://x.com/karpathy/status/2039805659525644595
1313

1414
I've been building exactly this.
1515

16-
Palinode: git-versioned markdown memory for AI agents. Hybrid BM25+vector search. 17 MCP tools. Deterministic compaction.
16+
Palinode: git-versioned markdown memory for AI agents. Hybrid BM25+vector search. 18 MCP tools. Deterministic compaction.
1717

1818
The part I added? git blame on every fact your agent knows.
1919

@@ -40,39 +40,35 @@ Same philosophy. With provenance.
4040

4141
**Tweet 4 (with status screenshot):**
4242

43-
227 files. 2,230 chunks indexed. 56 tests. 17 MCP tools. No cloud. No external DB. SQLite-vec + FTS5 + BGE-M3.
43+
227 files. 2,230 chunks indexed. 92 tests. 18 MCP tools. No cloud. No external DB. SQLite-vec + FTS5 + BGE-M3.
4444

4545
Runs on a single box. MIT license.
4646

4747
github.com/Paul-Kyle/palinode
4848

4949
---
5050

51-
## Show HN (Monday ~8am ET / 5am PT)
51+
## Show HN (Wednesday ~9am PT)
5252

5353
**Title:**
54-
Show HN: Palinode – Persistent agent memory as plain markdown with git provenance
54+
Show HN: Palinode – Git-versioned markdown memory for AI agents
5555

56-
**Body:**
57-
Palinode is persistent memory for AI agents. Your agent's memory is a folder of markdown files — typed (people, projects, decisions, insights), git-versioned, and searchable with hybrid BM25 + vector.
56+
**Body (post as first comment):**
57+
I was using Mem0 for agent memory and found myself SSHing into a box to grep Qdrant vectors trying to figure out when my agent learned something wrong. I wanted `git blame` for agent memory. So I built it.
5858

59-
The architecture is simple: markdown files are truth, SQLite (vec + FTS5) is a derived index, and every interface (MCP, REST API, CLI, agent plugin) hits the same backend. Set up on a server, connect from any IDE on any machine.
59+
Palinode stores your agent's memory as typed markdown files (people, projects, decisions, insights) with YAML frontmatter. A file watcher indexes them into SQLite-vec + FTS5 for hybrid search. Weekly, an LLM proposes structured compaction ops (KEEP/UPDATE/MERGE/SUPERSEDE/ARCHIVE) and a deterministic executor applies them — the LLM never writes files directly. Every compaction is a git commit.
6060

61-
What made me build this:
61+
The part I think is actually new: diff, blame, rollback, and push are MCP tools your agent can call. Not just git-compatible files — the agent can trace any fact back to the session that recorded it, or revert a bad compaction, without you touching a terminal.
6262

63-
I was using Mem0, then found myself grepping the Qdrant vectors trying to figure out when my agent learned something wrong. I wanted `git blame` for agent memory. So I built it.
63+
Architecture is dumb on purpose. Markdown files are truth. SQLite is a derived index. If everything crashes, `cat` still works. One API server, one .db file, one directory.
6464

65-
What's different:
65+
It runs on a homelab box. I connect from two laptops over Tailscale. The MCP server is a pure HTTP client with no state — works with Claude Code, Cursor, Zed, anything that speaks MCP. Same 18 tools are also available as a REST API and CLI.
6666

67-
- **Files are truth** — if every service crashes, `cat` still works. Rebuild the index anytime.
68-
- **Git operations as agent tools** — diff, blame, rollback, push are callable MCP tools, not just CLI conveniences.
69-
- **Deterministic compaction** — an LLM proposes structured ops (KEEP/UPDATE/MERGE/SUPERSEDE/ARCHIVE), a deterministic executor applies them and commits. The LLM never writes files directly.
70-
- **One backend, every interface** — MCP server (Streamable HTTP or stdio), REST API, CLI, OpenClaw plugin. Same 18 tools everywhere. Connect Claude Code, Zed, Cursor, Claude Desktop, or your own scripts.
71-
- **No infrastructure** — SQLite-vec + FTS5 + Ollama. No Postgres, no Redis, no cloud. One directory, one .db file, one API server.
67+
Karpathy's knowledge-base gist (https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) articulated a lot of what I was already building toward — particularly the raw/compiled split, which maps directly to Palinode's ingest/consolidate cycle. This is one working implementation of those ideas.
7268

73-
Stack: Python 3.11+, BGE-M3 embeddings via Ollama, any chat model for consolidation. 56 tests. MIT.
69+
What it doesn't do: no auto-injection into arbitrary LLM calls (you need an MCP client or to call the API). No multi-user. No cloud hosted version. It's a personal tool for one human and their agents.
7470

75-
I run it on a homelab box and connect from two laptops over Tailscale. The MCP server is a pure HTTP client — it holds no state, just proxies to the API.
71+
Python 3.11+, BGE-M3 via Ollama, any chat model for consolidation. 92 tests. MIT.
7672

7773
https://github.com/Paul-Kyle/palinode
7874

@@ -100,7 +96,7 @@ It works from any IDE — the MCP server runs over Streamable HTTP, so Claude Co
10096

10197
Browse your agent's brain in Obsidian. If Ollama dies, cat and grep still work.
10298

103-
18 tools, 56 tests, MIT: https://github.com/Paul-Kyle/palinode
99+
18 tools, 92 tests, MIT: https://github.com/Paul-Kyle/palinode
104100

105101
---
106102

@@ -116,6 +112,6 @@ The architecture: markdown files → SQLite-vec + FTS5 hybrid index → 4-phase
116112

117113
The design bet: files are the source of truth, everything else is a derived index. One backend, multiple interfaces (MCP server over Streamable HTTP, REST API, CLI, OpenClaw plugin). 18 tools work identically across Claude Code, Zed, Cursor, or shell scripts.
118114

119-
Behavioral spec in PROGRAM.md. 56 tests. MIT.
115+
Behavioral spec in PROGRAM.md. 92 tests. MIT.
120116

121117
https://github.com/Paul-Kyle/palinode

palinode/migration/mem0_classify.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
python -m palinode.migration.mem0_classify
1212
1313
Input:
14-
~/clawd/palinode/migration/mem0_export.json
14+
{PALINODE_DIR}/migration/mem0_export.json
1515
1616
Output:
17-
~/clawd/palinode/migration/mem0_classified.json
17+
{PALINODE_DIR}/migration/mem0_classified.json
1818
1919
LLM Config:
20-
URL: http://localhost:8080/v1 (Mac Studio Qwen 72B)
21-
Model: /path/to/models/qwen25-72b-abliterated-mlx
20+
URL: PALINODE_CLASSIFY_LLM_URL (default: http://localhost:8080)
21+
Model: PALINODE_CLASSIFY_LLM_MODEL (any OpenAI-compatible chat model)
2222
"""
2323
from __future__ import annotations
2424

@@ -113,17 +113,17 @@ def deduplicate(memories: list[dict]) -> list[dict]:
113113
- Config: system configuration or technical setup detail
114114
- Skip: not worth keeping (too vague, trivially obvious, or stale operational detail)
115115
116-
2. **entities**: Array of entity references, e.g. ["person/paul", "project/mm-kmd"]
117-
Known entities: person/paul, person/peter, person/aidan, project/mm-kmd, project/palinode, project/color-class, project/infrastructure
116+
2. **entities**: Array of entity references, e.g. ["person/alice", "project/my-app"]
117+
Detect entities from the content. Use the pattern: person/{name}, project/{slug}.
118118
119119
3. **group**: A short slug for grouping related memories into the same file.
120120
Related memories about the same topic should share a group slug.
121-
Examples: "mm-kmd-lora-training", "paul-preferences", "infrastructure-vllm"
121+
Examples: "my-app-milestones", "alice-preferences", "infrastructure-setup"
122122
123123
Return a JSON array with one object per memory:
124124
```json
125125
[
126-
{"index": 0, "type": "ProjectSnapshot", "entities": ["project/mm-kmd"], "group": "mm-kmd-milestones"},
126+
{"index": 0, "type": "ProjectSnapshot", "entities": ["project/my-app"], "group": "my-app-milestones"},
127127
{"index": 1, "type": "Skip", "entities": [], "group": ""},
128128
...
129129
]

palinode/migration/mem0_export.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
python -m palinode.migration.mem0_export
99
1010
Output:
11-
~/clawd/palinode/migration/mem0_export.json
11+
{PALINODE_DIR}/migration/mem0_export.json
1212
"""
1313
from __future__ import annotations
1414

@@ -24,7 +24,10 @@
2424
logger = logging.getLogger("palinode.migration.mem0_export")
2525

2626
QDRANT_URL = "http://localhost:6333"
27-
COLLECTIONS = ["mem0_attractor", "mem0_governor", "mem0_gradient"]
27+
COLLECTIONS = os.environ.get(
28+
"PALINODE_MEM0_COLLECTIONS",
29+
"mem0_default"
30+
).split(",")
2831
BATCH_SIZE = 100 # Qdrant scroll batch size
2932

3033

@@ -92,7 +95,7 @@ def _scroll_collection(collection: str) -> list[dict]:
9295
"created_at": payload.get("createdAt", ""),
9396
"hash": payload.get("hash", ""),
9497
"session_type": payload.get("session_type", ""),
95-
"user_id": payload.get("userId", "clawd"),
98+
"user_id": payload.get("userId", "default"),
9699
})
97100

98101
offset = result.get("next_page_offset")

palinode/migration/mem0_generate.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
python -m palinode.migration.mem0_generate
99
1010
Input:
11-
~/clawd/palinode/migration/mem0_classified.json
11+
{PALINODE_DIR}/migration/mem0_classified.json
1212
1313
Output:
14-
Markdown files in ~/clawd/palinode/{category}/
14+
Markdown files in {PALINODE_DIR}/{category}/
1515
"""
1616
from __future__ import annotations
1717

palinode/migration/run_mem0_backfill.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def main():
4848
logger.info(f"Total files: {sum(stats.values())}")
4949
logger.info("")
5050
logger.info("Next steps:")
51-
logger.info(" 1. Review the generated files in ~/clawd/palinode/")
51+
logger.info(" 1. Review the generated files in your PALINODE_DIR")
5252
logger.info(" 2. Run 'curl -X POST http://localhost:6340/reindex' to index them")
5353
logger.info(" 3. Test search: 'curl -X POST http://localhost:6340/search -d {\"query\":\"test\"}'")
5454
logger.info(" 4. If satisfied, disable Mem0 autoRecall in OpenClaw config")

0 commit comments

Comments
 (0)