Skip to content
Agentmart
Submit a tool

memstate

Persistent, versioned memory via the memstated daemon.

Skill by equwal

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/equwal-memstate

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Persistent, versioned memory via the memstated daemon. Data lives in a single SQLite file on your machine. No cloud, no API key. Use for storing facts, recalling memory, managing projects, and full-text or semantic search of agent summaries. Supports Markdown and direct keypath = value assignment.

Use cases: documents, backend, data, agent-building

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Python package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/memstate

What's inside

Skill name
memstate
Description
Persistent, versioned memory via the memstated daemon. Data lives in a single SQLite file on your machine. No cloud, no API key. Use for storing facts, recalling memory, managing projects, and full-text or semantic search of agent summaries. Supports Markdown and direct keypath = value assignment.
License
MIT
Instructions
334 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (12)

  • SKILL.md
  • _client.py · scripts/
  • memstate_delete.py · scripts/
  • memstate_delete_project.py · scripts/
  • memstate_get.py · scripts/
  • memstate_history.py · scripts/
  • memstate_remember.py · scripts/
  • memstate_search.py · scripts/
  • memstate_set.py · scripts/
  • test_skill.py · scripts/
  • validate_via_mcp.py · scripts/
  • test_results.txt

SKILL.md (first lines)

# Memstate Memory Management

This skill talks to a local memstated daemon over HTTP loopback. The
daemon stores data in a SQLite file at `$MEMSTATE_DB` (default
`~/.memstate/memstate.db`). No API key. If `MEMSTATE_ADDR` is set, the
scripts attach to that daemon. Otherwise each script spawns a private
daemon on a random port for the duration of the script and stops it on
exit.

Scripts live in this skill's `scripts/` directory (installed at
`~/.claude/skills/memstate/scripts/`). All examples below assume you
run them from there or by absolute path.

## Core Concepts

| Concept | Description |
|---|---|
| **Project** | Top-level container for memories, keyed by `project_id`. Auto-created on first write. |
| **Keypath** | Dot-separated path (`decisions.auth_provider`) unique within a project. Stored exactly as you write it. Nothing is auto-prefixed. |
| **Memory** | One fact or markdown section stored at a keypath, with full version history. Memory ids are integers. |
| **Versioning** | A write to an existing keypath supersedes the old value. The response names the old version as `superseded` with a 40-word preview; `memstate_history.py` returns it in full. Writes are synchronous. Data is queryable when the script returns. |
| **Tombstone** | A delete adds a tombstone version. History is never destroyed. A new write to the keypath revives it. |

## Naming conventions: follow EXACTLY

Every deviation fragments the store into disconnected near-duplicates.

- **project_id**: Omit `--project`. Every script derives the default
  from the git repository name (or the directory basename), slugged to
  snake_case, so all sessions in one repository share one project
  automatically. Pass `--project` only to reach a DIFFERENT project,
  and then only an id that `memstate_get.py --list-projects` lists.
  Never invent a variant. `my-app`, `myapp`, and `my_app_dev` are three
  different projects.
- **keypath segments**: Lowercase snake_case only (`[a-z0-9_]`), joined
  by dots. Dates are `YYYY_MM_DD` inside a segment:
  `task.summary.2026_07_04`. Never `2026-07-04`, camelCase, or spaces.
- **keypath shape**: `<area>.<topic>` or `<area>.<topic>.<detail>`.
  Preferred area segments: `decisions`, `todo`, `notes`, `gotchas`,
  `questions`, `files`, `config`, `arch`, `task.summary.<date>`.
- **One keypath = one fact.** To update a fact, write the SAME keypath
  with the new value. Versioning keeps the old one. Do not create a
  sibling keypath for a new value of the same fact.
- **Git branches**: Keypaths describe the main/default branch unless
  stated otherwise. Facts that are only true on an unmerged branch go
  under `branches.<branch_slug>.<area>...`, with the branch name
  slugged to snake_case (`feature/foo-bar` →
  `branches.feature_foo_bar.todo`). When the branch merges, write the
  durable outcomes to normal top-level keypaths, then recursively
  delete the `branches.<branch_slug>` subtree. If the branch is
  abandoned, delete the subtree. Branch-independent knowledge
  (decisions taken, gotchas, architecture) always lives at the top
  level.
- **category**: The kind of memory. ONE lowercase word from `decision`,
  `config`, `status`, `note`, `gotcha`, `reference`, `learning`.
  Filterable in search.
- **topics**: Subject tags, lowercase snake_case (`auth,embeddings`).
  Search matches any listed topic.
- **source**: A short provenance string, for example `claude-code
  session 2026_07_04` or `user decision`. Shown in history.

## User scope: facts that are not about this project

Every memory lives in a project by default. Some facts are about the
user or the machine and hold in every repository: an installed tool, a
path, the Ollama URL, a working preference, the user's role. These go
in the reserved project `_user`. Every script reaches it with
`--scope user` (never with `--project`).

A fact belongs in the user scope only when ALL three hold:

1. It stays true if this repository is deleted. It is not about any code.
2. It is true in every repository, for this user or for this machine.
3. It describes the user or the host, not work. Never a decision, todo,
   task summary, note, or gotcha about code. Those stay in the project.

The daemon enforces this line with a keypath allowlist. A write outside
it returns HTTP 400 and nothing is stored. Allowed shapes:

| Shape | Meaning | Example |
|---|---|---|
| `preferences.<topic>` | stated global working preferences | `preferences.commit_style` |
| `profile.<topic>` | who the user is; never credentials | `profile.role` |
| `host.<host_slug>.env.<topic>` | OS, shell, paths, runtimes, ports | `host.mbp.env.go_bin` |
| `host.<host_slug>.tools.<topic>` | how an installed tool is configured | `host.mbp.tools.ollama_url` |

`<host_slug>` is the first label of the hostname, slugged like a project
id (`Matts-MBP.local` → `matts_mbp`). `memstate_get.py` prints it as
`user.host`. Reads prune other machines' `host.*` subtrees; searches with
`--scope user` drop them.

```bash
python3 scripts/memstate_set.py --scope user --keypath preferences.commit_style \
  --value "short subjects, no trailers" --category config
python3 scripts/memstate_set.py --scope user --keypath host.matts_mbp.tools.ollama_url \
  --value "http://127.0.0.1:11434, model qwen3-embedding:4b" --category config
python3 scripts/memstate_get.py --scope user --keypath preferences --include-content
```

Heading extraction (`memstate_remember.py --scope user` without
`--keypath`) fits only `## Preferences` and `## Profile`. Host facts need
an explicit `--keypath`. One bad section rejects the whole call.

Never store secrets, tokens, or credentials in any scope. The
denied-prompt rule applies to the user scope too.

## Session project (MCP sessions only)

The MCP proxy defaults every call to the repository of its working
directory, and that is almost always right. When the prompt is clearly
about another subject (for example "set up my nginx config" from the home
directory), the agent pins its session once with `project_name` on the
first tool call. An existing id pins freely. A new id also needs
`new_project=true` and is refused when it looks like an existing id
(`regress_tests` vs `regress_test`). One pin per session.

One rule for creating projects, enforced by the proxy and by these
scripts alike: a write never creates a project unless it targets the git
repository you are in, or the call carries `new_project=true` (scripts:

From equwal/ai-config, MIT.

More from equwal/ai-config

Signals

Stars
0
Forks
0
Open issues
0
Last commit (this folder)
Oct 11, 2026 (17 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from equwal

Cite this page

memstate skill. Agent Mart. https://agentmart.dev/skills/equwal-memstate (last updated 2026-10-24)