{"id":48757086,"url":"https://github.com/phasespace-labs/palinode","last_synced_at":"2026-04-27T01:01:24.226Z","repository":{"id":348355465,"uuid":"1197595444","full_name":"phasespace-labs/palinode","owner":"phasespace-labs","description":"The memory substrate for AI agents and developer tools. Git-versioned, file-native, MCP-first.","archived":false,"fork":false,"pushed_at":"2026-04-20T05:15:32.000Z","size":680,"stargazers_count":19,"open_issues_count":20,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-20T07:15:24.899Z","etag":null,"topics":["agent-memory","ai-agent","git-versioned","llm","mcp","memory","openclaw","sqlite-vec","vector-search"],"latest_commit_sha":null,"homepage":"https://phasespace.co","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phasespace-labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"Paul-Kyle"}},"created_at":"2026-03-31T17:57:16.000Z","updated_at":"2026-04-20T05:13:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/phasespace-labs/palinode","commit_stats":null,"previous_names":["paul-kyle/palinode","phasespace-labs/palinode"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/phasespace-labs/palinode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phasespace-labs%2Fpalinode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phasespace-labs%2Fpalinode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phasespace-labs%2Fpalinode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phasespace-labs%2Fpalinode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phasespace-labs","download_url":"https://codeload.github.com/phasespace-labs/palinode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phasespace-labs%2Fpalinode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32318417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"ssl_error","status_checked_at":"2026-04-26T23:26:25.802Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-memory","ai-agent","git-versioned","llm","mcp","memory","openclaw","sqlite-vec","vector-search"],"created_at":"2026-04-13T03:20:01.563Z","updated_at":"2026-04-27T01:01:24.185Z","avatar_url":"https://github.com/phasespace-labs.png","language":"Python","funding_links":["https://github.com/sponsors/Paul-Kyle"],"categories":[],"sub_categories":[],"readme":"\u003c!-- mcp-name: io.github.phasespace-labs/palinode --\u003e\n\n```\n┌─ palinode ─┐\n│ ░░░░░░░░░░ │\n│ ▓▓▓▓▓▓▓▓▓▓ │\n│ ██████████ │\n└────────────┘\n```\n\n**The memory substrate for AI agents and developer tools. Git-versioned, file-native, MCP-first.**\n\nYour agent's memory is a folder of markdown files. Palinode indexes them with hybrid search, compacts them with an LLM, and serves them through MCP — so the same memory works in Claude Code, Cursor, Windsurf, Zed, VS Code (Continue/Cline), and any other MCP-compatible editor. Enterprises can govern AI memory the same way they govern code. If every service crashes, `cat` still works.\n\n*A palinode is a poem that retracts what was said before and says it better. That's what memory compaction does.*\n\n---\n\n## The Idea\n\nMost agent memory is a black box. You can't read it, you can't diff it, you can't `grep` it when the vector DB is down. Palinode bets on **plain files as the source of truth** and builds everything else as a derived index.\n\n```\nFiles (markdown + YAML frontmatter)\n  ↓ watched\nIndex (SQLite-vec vectors + FTS5 keywords, single .db file)\n  ↓ queried by\nInterfaces (MCP server, REST API, CLI, OpenClaw plugin)\n  ↓ compacted by\nLLM (proposes ops → deterministic executor applies them → git commits)\n```\n\nThat's the whole architecture. One directory of `.md` files, one SQLite database, one API server. No Postgres, no Redis, no cloud dependency.\n\n---\n\n## One Backend, Every Interface\n\nPalinode doesn't care how you talk to it. The same 17 tools work everywhere:\n\n| Interface | Transport | Best For |\n|-----------|-----------|----------|\n| **MCP Server** | Streamable HTTP or stdio | Claude Code, Claude Desktop, Cursor, Windsurf, Zed, VS Code (Continue/Cline) |\n| **REST API** | HTTP on :6340 | Scripts, webhooks, custom integrations |\n| **CLI** | Wraps REST API | Cron jobs, SSH, shell scripts (8x fewer tokens than MCP) |\n| **Plugin** | OpenClaw lifecycle hooks | Agent frameworks with inject/extract patterns |\n\nSet up once on a server. Connect from any machine, any IDE, any agent framework. The MCP server is a pure HTTP client — it holds no state, no database connection, no embedder. Point it at the API and go.\n\n```json\n{\n  \"mcpServers\": {\n    \"palinode\": { \"url\": \"http://your-server:6341/mcp/\" }\n  }\n}\n```\n\nThat's the entire client config. Works with Claude Code, Claude Desktop, Cursor, Windsurf, Zed, and VS Code (Continue/Cline). See [docs/MCP-SETUP.md](docs/MCP-SETUP.md) for editor-specific paths.\n\n---\n\n## How It Works\n\n**Store** — Typed markdown files (people, projects, decisions, insights) with YAML frontmatter. Git-versioned. Human-readable. Editable in Obsidian, VS Code, vim, or anything.\n\n**Index** — A file watcher embeds with BGE-M3 and indexes with FTS5 as you save. Content-hash dedup skips re-embedding unchanged files (~90% savings). Single SQLite file, zero external services.\n\n**Search** — Hybrid BM25 + vector search merged with Reciprocal Rank Fusion. Keyword precision when you need exact terms, semantic recall when you don't. Optional associative entity graph and prospective triggers.\n\n**Compact** — Weekly consolidation where an LLM proposes structured operations (KEEP / UPDATE / MERGE / SUPERSEDE / ARCHIVE) and a deterministic executor applies them. The LLM never touches your files directly. Every compaction is a git commit you can review, blame, or revert.\n\n**Audit** — `git blame` any fact. `git diff` any change. `rollback` any mistake. These aren't just git-compatible files — `palinode_diff`, `palinode_blame`, and `palinode_rollback` are first-class tools your agent can call.\n\n---\n\n## Getting started in 60 seconds (Claude Code)\n\nAlready have Palinode installed and `palinode-api` running? Drop it into any\nproject in one command:\n\n```bash\ncd your-project\npalinode init\n```\n\nThat scaffolds:\n\n- `.claude/CLAUDE.md` — memory instructions for the agent (appended if one\n  already exists)\n- `.claude/settings.json` — a `SessionEnd` hook that auto-captures on `/clear`,\n  logout, and normal exit\n- `.claude/hooks/palinode-session-end.sh` — the hook script itself\n- `.mcp.json` — points Claude Code at the `palinode` MCP server\n\nOpen the project in Claude Code and your agent will search prior context on\nstartup, save decisions as you work, and snapshot the session on `/clear`. No\nserver restarts, no settings menus, no copy-paste.\n\nRe-run with `--dry-run` to preview, `--force` to overwrite, or `--no-mcp`\n/ `--no-hook` to scope what gets installed.\n\n---\n\n## Quick Start\n\n```bash\n# Install\ngit clone https://github.com/phasespace-labs/palinode \u0026\u0026 cd palinode\npython3 -m venv venv \u0026\u0026 source venv/bin/activate\npip install -e .\n\n# Create your memory directory\nmkdir -p ~/.palinode/{people,projects,decisions,insights,daily}\ncd ~/.palinode \u0026\u0026 git init\ncp /path/to/palinode/palinode.config.yaml.example palinode.config.yaml  # adjust path\n\n# Start services\nPALINODE_DIR=~/.palinode palinode-api        # REST API on :6340\nPALINODE_DIR=~/.palinode palinode-watcher     # auto-indexes on file save\nPALINODE_DIR=~/.palinode palinode-mcp-sse     # MCP server on :6341 (optional)\n\n# Verify\ncurl http://localhost:6340/status\n```\n\n\u003e Your memory directory is **private**. It contains personal data. Never make it public. The code repo contains zero memory files.\n\n\u003e For a pre-populated demo, copy `examples/sample-memory/` to `~/.palinode/`.\n\n---\n\n## Usage Examples\n\n### Save a decision, recall it later\n\n```bash\n# During a session — save a decision\npalinode save --type Decision \"Chose SQLite over Postgres for the cache layer. \\\n  Reason: no ops burden, single-file deployment, good enough for our scale.\"\n\n# Next week — search for it\npalinode search \"database decision for cache\"\n```\n\n### End-of-session capture\n\n```bash\n# Agent calls at end of coding session\npalinode session-end \\\n  --summary \"Migrated auth from JWT to session tokens\" \\\n  --decisions \"Session tokens stored server-side, 24h expiry\" \\\n  --blockers \"Need to update mobile client auth flow\"\n```\n\n### Audit trail — who decided what and when\n\n```bash\n# Trace a fact back to when it was recorded\npalinode blame decisions/auth-migration.md\n\n# See what changed across all memory in the last week\npalinode diff --days 7\n```\n\n---\n\n## Tools\n\n17 tools available through every interface:\n\n| Tool | What It Does |\n|------|-------------|\n| `search` | Hybrid BM25 + vector search with category filter |\n| `save` | Store a typed memory (person, decision, insight, project) |\n| `list` | Browse memory files by type, filter by core status |\n| `read` | Read the full content of a memory file |\n| `ingest` | Fetch a URL and save as research |\n| `status` | Health check — file counts, index stats, service status |\n| `entities` | Entity graph — cross-references between memories |\n| `consolidate` | Preview or run LLM-powered compaction |\n| `diff` | What changed in the last N days |\n| `blame` | Trace a fact back to the commit that recorded it |\n| `history` | Git history for a file with diff stats and rename tracking |\n| `rollback` | Revert a file to a previous commit (safe, creates new commit) |\n| `push` | Sync memory to a remote git repo |\n| `trigger` | Prospective recall — auto-inject when a topic comes up |\n| `lint` | Health scan — orphans, stale files, missing fields |\n| `session_end` | Capture summary, decisions, and blockers at end of session |\n| `prompt` | List, show, or activate versioned LLM prompts |\n\nEvery tool is accessible as `palinode_\u003cname\u003e` via MCP, `palinode \u003cname\u003e` via CLI, or `POST/GET /\u003cname\u003e` via the REST API.\n\n---\n\n## Stack\n\n| Layer | Choice | Why |\n|-------|--------|-----|\n| Source of truth | Markdown + YAML frontmatter | Human-readable, git-versioned, portable |\n| Vector index | SQLite-vec (embedded) | No server, single file, zero config |\n| Keyword index | SQLite FTS5 (embedded) | BM25 for exact terms, zero dependencies |\n| Embeddings | BGE-M3 via Ollama | Local, private, no API key needed |\n| API | FastAPI | Lightweight, async, one process |\n| MCP | Python MCP SDK (Streamable HTTP) | Works with every IDE over the network |\n| CLI | Click (wraps REST API) | Shell-native, TTY-aware output |\n| Behavior | [`PROGRAM.md`](PROGRAM.md) | What to remember, how to extract, how to compact — edit one file to change all behavior |\n\n---\n\n## Memory File Format\n\n```yaml\n---\nid: project-palinode\ncategory: project\nname: Palinode\ncore: true\nstatus: active\nentities: [person/paul]\nlast_updated: 2026-04-05T00:00:00Z\nsummary: \"Persistent memory for AI agents.\"\ncanonical_question: \"What is Palinode and what does it do?\"\n---\n# Palinode\n\nYour content here. As detailed or brief as you want.\nFiles marked `core: true` are always in context.\nEverything else is retrieved on demand via hybrid search.\nThe `canonical_question` field anchors the file to the question it answers, improving search relevance.\n```\n\nOpen your memory directory as an [Obsidian](https://obsidian.md) vault for visual browsing. See [docs/OBSIDIAN-SETUP.md](docs/OBSIDIAN-SETUP.md).\n\n---\n\n## Configuration\n\nAll behavior is in `palinode.config.yaml`:\n\n```yaml\nmemory_dir: \"~/.palinode\"\nollama_url: \"http://localhost:11434\"\nembedding_model: \"bge-m3\"\n\nrecall:\n  search:\n    top_k: 5\n    threshold: 0.4\n  core:\n    max_chars_per_file: 3000\n\nsearch:\n  hybrid_enabled: true\n  hybrid_weight: 0.5         # 0.0 = vector only, 1.0 = BM25 only\n\nconsolidation:\n  llm_model: \"llama3.1:8b\"   # any chat model that outputs JSON\n  llm_url: \"http://localhost:11434\"\n  llm_fallbacks:              # tried in order if primary fails\n    - model: \"qwen2.5:14b-instruct\"\n      url: \"http://localhost:11434\"\n```\n\nAll models are swappable. Any Ollama embedding model, any OpenAI-compatible chat endpoint. See [palinode.config.yaml.example](palinode.config.yaml.example) for the full reference.\n\n---\n\n## Requirements\n\n- **Python 3.11+**\n- **Ollama** with `bge-m3` (`ollama pull bge-m3`)\n- **Git**\n\nOptional: a chat model for consolidation (any 7B+ works), OpenClaw for agent plugin hooks.\n\n---\n\n## API Reference\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `GET` | `/status` | Health check + stats |\n| `POST` | `/search` | Hybrid search with filters |\n| `POST` | `/search-associative` | Entity graph traversal |\n| `POST` | `/save` | Create a typed memory file |\n| `POST` | `/ingest-url` | Fetch URL, save as research |\n| `GET/POST` | `/triggers` | Prospective recall triggers |\n| `POST` | `/consolidate` | Run or preview compaction |\n| `GET` | `/list` | Browse files by type |\n| `GET` | `/read?file_path=...` | Read a memory file |\n| `GET` | `/history/{file_path}` | Git log for a file |\n| `GET` | `/diff` | Recent changes |\n| `GET` | `/blame/{file_path}` | Git blame |\n| `POST` | `/rollback` | Revert a file |\n| `POST` | `/push` | Push to git remote |\n| `POST` | `/reindex` | Rebuild indices |\n| `POST` | `/session-end` | Capture session summary |\n| `POST` | `/lint` | Health scan |\n\n---\n\n## Design Principles\n\n1. **Files are truth.** Not databases, not vector stores. Markdown files that humans can read, edit, and version with git.\n\n2. **Typed, not flat.** People, projects, decisions, insights — each has structure. This enables reliable retrieval and consolidation.\n\n3. **Consolidation, not accumulation.** 100 sessions should produce 20 well-maintained files, not 100 unread dumps.\n\n4. **Invisible when working.** The human talks to their agent. Palinode works behind the scenes.\n\n5. **Graceful degradation.** Vector index down? Read files directly. Embedding service down? Grep. Machine off? It's a git repo, clone it anywhere.\n\n6. **Zero taxonomy burden.** The system classifies. The human reviews. If the human has to maintain a taxonomy, the system dies.\n\n---\n\n## What's Unique\n\n- **Your data, your files** — No accounts, no cloud dependency, no vendor lock-in. Your memory is markdown files in a directory you control. Export is `cp`. Backup is `git push`. Whatever happens to any tool in this ecosystem, your data is plain text on your filesystem.\n- **Cross-IDE memory** — Your memory lives in one place. Connect from Claude Code, Cursor, Windsurf, Zed, or any MCP-compatible editor. Switch IDEs without losing context.\n- **Git operations as agent tools** — `diff`, `blame`, `rollback`, `push` exposed via MCP. No other system makes git ops callable by the agent.\n- **Operation-based compaction** — KEEP/UPDATE/MERGE/SUPERSEDE/ARCHIVE DSL. LLM proposes, deterministic executor disposes. Every compaction is a reviewable git commit.\n- **Per-fact addressability** — `\u003c!-- fact:slug --\u003e` IDs inline in markdown, invisible in rendering, preserved by git, targetable by compaction.\n- **4-phase injection** — Core (always) + Topic (per-turn search) + Associative (entity graph) + Triggered (prospective recall).\n- **Multi-transport MCP** — stdio for local, Streamable HTTP for remote. One server, any IDE on any machine.\n- **If everything crashes, `cat` still works.**\n\n---\n\n## Acknowledgments\n\nPalinode builds on ideas from [Karpathy's LLM Knowledge Bases](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f), [Letta](https://github.com/letta-ai/letta) (tiered memory), and [LangMem](https://github.com/langchain-ai/langmem) (typed schemas + background consolidation). See [docs/ACKNOWLEDGMENTS.md](docs/ACKNOWLEDGMENTS.md) for the full list.\n\nSee also the [epistemic integrity discussion](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) in the Karpathy gist thread — particularly the problem of LLM wikis that \"synthesise without citing, drift from sources without knowing it, and present false certainty where disagreement exists.\" Git-based provenance is Palinode's answer to that problem.\n\nIf you know of prior art we missed, please [open an issue](https://github.com/phasespace-labs/palinode/issues).\n\n---\n\n## License\n\nMIT — [Privacy Policy](PRIVACY.md)\n\n---\n\n*Built by [Paul Kyle](https://github.com/Paul-Kyle) with help from AI agents who use Palinode to remember building Palinode.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphasespace-labs%2Fpalinode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphasespace-labs%2Fpalinode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphasespace-labs%2Fpalinode/lists"}