npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

clankervault

v0.1.1

Published

Clankervault: portable memory for AI tools, compiled from one plain-markdown vault into CLAUDE.md, AGENTS.md, .cursorrules and more.

Readme

Clankervault

CI npm license

Wherever you talk to AI, you're talking to someone who knows you.

Clankervault is a portable memory layer for AI coding and creative tools. You keep one plain markdown vault on disk, in a format you own and can read without any tool. clanker compile turns it into the native context files each assistant already looks for: CLAUDE.md, AGENTS.md, .cursorrules. Write your facts, recipes, decisions and taste once, and every tool you switch to picks up the same memory instead of starting from zero.

The five record kinds

Everything you write into a project is one of these. Four are append-only (you never edit an old one, you supersede it); state is the one file you overwrite directly, because it tracks what is happening right now.

| Kind | ID prefix | Mutability | What it holds | |------|-----------|------------|----------------| | fact | fct | append-only | Stable facts: stack, endpoints, accounts, constraints | | recipe | rcp | append-only | How something is done here: repeatable steps | | decision | dec | append-only | A choice made, and why, so it does not get relitigated | | taste | tst | append-only | Preferences and style: tone, conventions, things to avoid | | state | (none, one state.md) | mutable, overwritten | What is in progress right now |

fact, recipe, decision and taste records also carry status (unconfirmed, confirmed or superseded) and confidence (high, medium, low). Records written by hand through clanker add are confirmed/high by default; unconfirmed records come from an assistant proposing memory live through the MCP server's remember tool, or from clanker mine reading your AI session transcripts (see MCP server and Mining below), and only take effect once a human confirms them.

Vault structure

~/vault/                    (default; override with VAULT_DIR)
├── vault.yaml              spec version, compile.token_budget
├── device.yaml             per-device, never synced (see Anchors below)
├── me/
│   ├── profile.md          who you are, tone and language preferences
│   ├── taste/              global taste files, one concern per file
│   └── skills/
└── projects/
    └── <project-id>/
        ├── project.md      identity + facts, frontmatter: id, name, aliases, kind, roots
        ├── state.md        the one mutable file
        └── records/
            └── <date>-<slug>.md   one fact/recipe/decision/taste record

Install

This is unreleased software: the package is not on the npm registry yet. Once published:

npm i -g clankervault

For now, install from source:

git clone <this repo> clankervault && cd clankervault
npm install
npm run build
npm link          # puts `clanker` on your PATH

During development you can run the CLI straight from src/cli.ts with tsx, no build step needed: npm run dev -- <args> (the -- passes the arguments through), e.g. npm run dev -- init ~/vault.

Quickstart

clanker setup

That single command is the intended way to start using Clankervault. It looks at this machine, tells you what it found, and asks before it touches anything (pass --yes to accept every default without prompting, or --dry-run to see the plan without changing a thing). One run:

  1. Creates ~/vault if you do not have one yet (override with VAULT_DIR or --vault).
  2. Detects which AI tools are installed: Claude Code, Codex, Cursor, Gemini CLI, Claude Desktop, Windsurf, by looking for each tool's own config directory. Nothing here assumes Claude Code is the only tool in play.
  3. Discovers your projects by reading the cwd field out of session transcripts these tools already keep on disk (Claude Code's ~/.claude/projects/, and Codex's ~/.codex/sessions/, which also carries cwd per session). It never guesses a project from an encoded directory name, only from what a real transcript says its working directory was, and it registers each one it finds (skipping anything that does not exist on disk anymore, or that a project already covers).
  4. Wires each detected tool to serve compiled context natively (see the per-tool table below), and prints the one manual step or two that need a human hand (a claude mcp add command, a Codex TOML snippet), because those need a CLI session or a config format Clankervault will not silently edit.
  5. Fast-forwards clanker mine's offsets so mining starts from now rather than trying to read months of transcript history on its first run.
  6. Offers the free local refresh daemon and prints how to turn on the paid mining daemon (see Daemons below).
  7. Compiles the vault into every adapter the detected tools need, for every project it just registered.

If you would rather do it by hand, the pieces clanker setup wires together are the same commands used everywhere else in this README:

clanker init                                    # creates ~/vault
clanker project new "My App" --root ~/dev/my-app
cd ~/dev/my-app
clanker add decision "Use Postgres over SQLite" -b "need concurrent writers"
clanker compile                                 # writes CLAUDE.md, AGENTS.md, .cursorrules here

clanker compile writes into the current directory by default (--out <dir> to target elsewhere) and always stamps a GENERATED header, because these files are disposable views of the vault, not the source of truth. Add them to your project's .gitignore; the vault itself is what you keep. clanker compile --all does the same for every registered project at once, into the first existing path root each one has, and is what both clanker setup and the refresh daemon call underneath.

Per-tool behavior

| Tool | Detected by | What clanker setup does | |------|-------------|--------------------------| | Claude Code | ~/.claude exists | Compiles CLAUDE.md into each project. Adds a SessionStart hook to ~/.claude/settings.json that reruns clanker compile --tool claude at the start of every session, so the file never goes stale. Prints claude mcp add clankervault -- clanker mcp for you to run yourself (it needs the claude CLI and your own login, so Clankervault never runs it for you). | | Codex | ~/.codex exists | Compiles AGENTS.md into each project. Codex config is TOML, which Clankervault never edits; instead it prints a ready-to-paste [mcp_servers.clankervault] snippet for ~/.codex/config.toml. | | Cursor | ~/.cursor exists | Compiles .cursorrules into each project. Merges mcpServers.clankervault into ~/.cursor/mcp.json, creating the file if it does not exist and preserving every other key already in it. | | Gemini CLI | ~/.gemini exists | Compiles GEMINI.md into each project (Gemini CLI reads this file natively; no MCP wiring yet). | | Claude Desktop | ~/Library/Application Support/Claude exists | Compiles CLAUDE.md (same adapter as Claude Code). Merges mcpServers.clankervault into claude_desktop_config.json, same idempotent merge as Cursor. | | Windsurf | ~/.windsurf exists | Compiles .windsurfrules into each project. |

Every config file clanker setup edits is read, merged and written back with every other key preserved, and gets a one-time <file>.bak-vault copy of what was there before the first edit. Re-running clanker setup is safe: it never adds a duplicate hook entry and never re-registers a project it already knows about.

Daemons

clanker setup can install two background jobs, and treats them very differently because one is free and one costs money:

  • Refresh daemon (dev.clankervault.refresh, macOS launchd, hourly): runs clanker compile --all. This is a purely local operation, no network calls, so clanker setup may install and load it automatically once you say yes. On non-macOS it prints an equivalent cron line instead of writing a plist.
  • Mining daemon: runs clanker mine, which shells out to the claude CLI to read new session transcripts, so it costs whatever that CLI call costs against your own account. clanker setup never turns this on for you; it only fast-forwards the mining offsets (so a future run starts from "now", not from months of history) and prints the launchctl load line you would run yourself to enable it on a schedule.

Append-only and supersede

Records are never edited in place. When you change your mind, you run clanker supersede <old-id> "<new title>": it writes a brand new record, links it back with supersedes, and flips the old record's status to superseded and superseded_by to the new id. The old body is left untouched, so the history of what you used to believe, and when it changed, stays on disk. Superseded records are skipped at compile time.

state.md is the deliberate exception: clanker state "<text>" overwrites it directly, because "what I'm doing right now" is not something worth version-history for, it just needs to be current.

Project identity

A project is identified by a stable generated id (<slug>-<4 hex chars>, e.g. my-app-a1b2), and clanker resolves which project you mean from your current directory through, in order:

  1. a .vault-id file (containing just the project id) anywhere from your cwd up to the filesystem root
  2. this device's projects map in device.yaml (project-id: /local/path)
  3. a matching git remote, if any of the project's roots recorded one
  4. a path prefix match against the project's recorded roots

Pass --project <id-or-name> to any command to skip resolution entirely. --root and --git on clanker project new are how you record roots; they are repeatable flags, so a project can be recognized from more than one checkout or remote.

Anchors and availability

Paths written into records should never be hardcoded absolute paths, because a vault is meant to move between machines. Instead you write {project_root} or a free-form {name} anchor, and device.yaml, which is per-device and never synced, resolves them locally: projects maps {project_root} per project id, anchors maps any other {name} to wherever it lives on this machine (an external drive, a NAS mount, and so on).

This is also why a record can carry availability frontmatter: a per-device map of where an asset actually sits, or null if it is confirmed absent there. At compile time this renders as a contextual note, e.g. "NOT on this device (mini); macbook: /path, nas: /path". Clankervault never syncs the assets themselves, it syncs knowledge about them: where they are, and where they are not, on whichever device you are compiling from.

Token budget and priorities

clanker compile condenses every record to one line (title, first meaningful body line, id reference) and fits as many as it can into compile.token_budget from vault.yaml (default 4000, override per run with --budget). Project identity, your profile, state.md, global taste and unconfirmed-but-high-confidence records always ship in full; only per-type record lines get cut once the budget runs out, kept in this order (leftmost survives longest, rightmost is cut first):

  • code projects: state > decisions > recipes > taste > facts
  • creative projects: state > taste > recipes > decisions > facts

Nothing is deleted: cut lines just do not make it into this particular compile. Raise compile.token_budget in vault.yaml, or the record still lives in projects/<id>/records/ on disk.

Adapters

Each output target is a small, pluggable module implementing:

interface Adapter {
  name: string;
  filename: string;
  render(ctx: CompiledContext): string;
}

src/adapters/index.ts holds the registry (adapters, getAdapter) and a shared renderMarkdownBody helper used by the markdown-flavored targets. Shipped today: claude (CLAUDE.md), agents (AGENTS.md), cursor (.cursorrules), gemini (GEMINI.md) and windsurf (.windsurfrules). TOOL_ADAPTERS maps each detected AI tool to the adapter it needs (used by clanker setup; see the per-tool table above). Adding a new tool means writing one more adapter file and registering it, nothing else in the CLI or compiler needs to change.

Sync

clanker sync reconciles a vault edited from more than one device, without git. In folder mode there is no server and no cloud account: the remote is just a folder, so anything that already keeps a folder in sync between your machines works, iCloud Drive, Dropbox, a NAS mount, a USB drive. The http mode below (see Self-hosting) talks to your own self-hosted clanker serve instead. clanker only ever writes encrypted objects into whichever remote you configured; the storage side (v1 ships dir, a plain directory backend, and http, talking to clanker serve) is a small pluggable interface, open to further backends without changing anything else.

Everything that leaves this machine is end-to-end encrypted first: file contents, file paths and the manifest that lists them are all encrypted with a key derived from your passphrase, so whatever holds the remote folder (iCloud, a NAS, a USB stick you lose) never sees plaintext content or even readable filenames. Only a random salt sits on the remote unencrypted, since key derivation needs it.

Setup on two devices, once each, pointing at the same remote path with the same passphrase:

clanker sync setup --path /path/to/shared/folder --passphrase <same-on-every-device>

Omit --passphrase and set VAULT_PASSPHRASE in your shell environment instead if you would rather not have it sitting in device.yaml. Either way, the passphrase must be identical on every device: it is what lets two machines decrypt each other's objects and is never itself transmitted.

Then, on any device:

clanker sync              # one-shot: pull and push whatever changed, print a summary
clanker sync --watch      # keep running: initial sync, then sync on every local change
                           # (1.5s debounce) plus a periodic sync every --interval seconds (default 30)

--watch runs until you stop it (Ctrl+C) and is meant for a machine you leave open, so continuous small edits go out as continuous small diffs instead of one large sync later.

Conflict semantics. The four append-only record kinds merge for free: each record is its own file with a generated name, so two devices adding records under records/ never collide. A true conflict can only happen on a file you hand-edit directly and that keeps the same path across devices, state.md, me/profile.md, a project's project.md, or vault.yaml, when both devices change it since the last sync. clanker sync resolves that with last-write-wins by modification time, and the losing version is never silently discarded: it is written next to the file it lost to as a timestamped <name>.conflict-<device>-<stamp>.md copy, which also syncs to every other device, so you can always go read what the other side had and recover it by hand if last-write-wins picked wrong.

Never synced, by design, spec §7: device.yaml (per-device settings: device name, anchors, project root map, sync config itself), .sync/ (this device's local sync state), .mine/, and .DS_Store. These describe this machine, not the vault's content, so they stay local on every device.

Known limitations, not solved in this phase: last-write-wins depends on roughly sane, roughly synchronized clocks across your devices, a device with a badly wrong clock can win conflicts it should lose. The directory backend's compare-and-swap on the manifest is best-effort, safe against the concurrent- write races this codebase creates and tests, but not a guarantee against every possible failure mode of arbitrary third-party sync software (iCloud, Dropbox) racing underneath it. The passphrase, when saved with --passphrase instead of VAULT_PASSPHRASE, sits in device.yaml in plaintext on that device.

MCP server

clanker compile writes files once, ahead of time; clanker mcp serves the vault live, on demand, to anything that speaks the Model Context Protocol (spec §5). This is the path for chat assistants that cannot read a compiled file off disk, and for any setup running multiple accounts of the same assistant, since each MCP client identifies itself in the handshake and gets its own provenance trail on what it wrote, rather than every account sharing one compiled file.

Run it with clanker mcp, or point a client at it directly. For Claude Desktop or Claude Code, add to the MCP server config:

{
  "mcpServers": {
    "clankervault": {
      "command": "clanker",
      "args": ["mcp", "--vault", "/path/to/your/vault"]
    }
  }
}

Drop "--vault", "/path/to/your/vault" if VAULT_DIR is already set, or if you are fine with the default ~/vault.

Four tools are exposed:

| Tool | Arguments | What it does | |------|-----------|----------------| | get_context | project?, lenses? | Compiled context for a project: facts, recipes, decisions, taste, state. Resolves the project the same way the CLI does (--project-style ref, else current directory) and falls back to just the user's profile and global taste plus a list of known projects when nothing resolves. | | get_state | project | The project's current work in progress (state.md), or "Nothing in progress." when it is empty. | | remember | project?, type, title, body?, scope?, tags? | Writes a new record from inside a conversation. | | search | query | Keyword search across every project's records. |

Trust model. A record written through remember is saved with status: unconfirmed and provenance source.tool: mcp:<client-name>, and it stays out of every compiled file and out of get_context until a human runs clanker confirm <id>, the same gate that already applies to any other unconfirmed record. An assistant proposing memory about you can never make that memory take effect on its own. get_context also takes a lenses argument: pass lenses: false when you want project facts and state without the personal layer (profile and taste), for a context you plan to hand to someone else or paste somewhere less private.

Self-hosting

clanker serve runs a small server that gives you two things from one process: an encrypted sync remote (the --url alternative to a shared folder, see Sync above) and a remote MCP endpoint at /v1/mcp for chat assistants that can reach the network but cannot launch a local clanker mcp stdio process, a hosted assistant, a phone, a teammate's machine.

clanker serve --data /path/to/server-data --port 8484

Token model. Every request needs Authorization: Bearer <token>. The token comes from --token, or VAULT_SERVER_TOKEN in the environment, or, if neither is set, a random one generated on first run and saved to <data>/token (owner-only, mode 0600), printed once to stdout so you can copy it to your devices. There is no per-user account system: one token per server, shared across every device you point at it.

Point a device at it the same way you would a shared folder:

clanker sync setup --url https://your-server:8484 --token <token> --passphrase <same-on-every-device>
clanker sync

The E2E tradeoff. By default, with no VAULT_PASSPHRASE in the server's own environment, clanker serve is a pure ciphertext store: exactly like syncing over a folder, it never sees plaintext, and /v1/mcp answers 503 rather than pretending to work. Setting VAULT_PASSPHRASE on the server enables /v1/mcp: the server decrypts a private working copy for itself (the replica, kept under <data>/replica, refreshed from the ciphertext store roughly every 15 seconds) so it has something to answer MCP tool calls with. That is a real, deliberate tradeoff, not a hidden one: it moves trust from "nothing but your own devices ever sees plaintext" to "your server, which you operate, sees plaintext too", and the startup log always states which mode is active:

MCP endpoint: enabled at /v1/mcp
MCP endpoint: disabled (set VAULT_PASSPHRASE to enable)

Every /v1/mcp request is processed one at a time, in arrival order, on a single queue: correct under concurrent writes from multiple assistants (never two at once scanning the decrypted replica, never a lost update), but this makes remote MCP a single-tenant convenience for one operator's own devices, not something built to serve many simultaneous users at scale.

Docker. The image builds from source (npm ci, tsc, then npm prune --omit=dev) and its entrypoint is clanker serve --data /data --port 8484:

docker build -t clankervault-server .
docker run -d \
  -p 8484:8484 \
  -v clankervault-data:/data \
  -e VAULT_SERVER_TOKEN=<pick-a-long-random-token> \
  -e VAULT_PASSPHRASE=<optional, enables remote MCP> \
  clankervault-server

/data holds the ciphertext store, the token file if you did not supply one, and, only when VAULT_PASSPHRASE is set, the decrypted replica: back it up like a vault, and treat the container's filesystem like you would any server that can hold decrypted user data when that variable is set.

This is the self-hostable half of what a hosted Clankervault service would need, one server, one token, your own machine or VPS. Running this for other people, multi-tenant accounts, billing, TLS termination, one-click deploy, is not built here; it is the natural paid tier on top, not a requirement to use Clankervault yourself.

Mining

clanker mine finds durable, reusable knowledge already sitting in your AI coding sessions and proposes it as unconfirmed records, so you do not have to write everything into the vault by hand. The first reader is Claude Code: it reads the JSONL transcripts Claude Code already keeps under ~/.claude/projects/, incrementally, one file at a time, tracking a byte offset per file so a run only ever looks at what is new since the last one. A trailing, not-yet-complete line is left for next time rather than parsed half-written.

Each new chunk of transcript text is resolved to a project the same way the CLI already does (.vault-id, device.yaml, git remote, path prefix, from the session's working directory), then handed to an extractor along with the titles of that project's existing, non-superseded records, so it can skip anything already known and flag genuine contradictions instead of silently duplicating. The shipped extractor shells out to the claude CLI already installed and logged into your own account, no separate API key, with a prompt that frames the transcript explicitly as data to analyze, not instructions to follow, and asks for at most five items and an empty array over noise.

clanker mine                 # one pass over new transcript data
clanker mine --dry-run       # show what would be created, write nothing
clanker mine --watch         # keep running, mine every --interval seconds (default 300)

Mined records are born unconfirmed, carry source: { tool: 'claude-code', transcript: <path>, approx_range: 'bytes <from>-<to>' }, and never compile or show up in get_context until a human confirms them, same as anything the MCP server proposes. Something that contradicts an existing record comes back tagged contradicts, its body prefixed with Contradicts: <old title>, for you to resolve by hand with clanker supersede; mined data never auto-supersedes a confirmed record.

Two ways out of unconfirmed: clanker confirm <id> by hand, or clanker settle --days <n> (default 14), which confirms every unconfirmed, confidence: high record older than that many days, for one project with --project or across all of them without it. clanker settle never touches medium- or low-confidence records, and never touches a record whose source.tool starts with mcp: anything an assistant proposed live through the MCP server still needs an explicit clanker confirm.

Per-file offsets live in .mine/offsets.json, already on the sync exclusion list (per-device, like device.yaml), since what a given machine has already read out of its own ~/.claude/projects/ has no meaning on another one.

Roadmap

Phase 1 (the format plus this CLI), phase 2 (sync), phase 3 (the MCP server), phase 4 (mining) and phase 5 (the self-hostable server: HTTP sync remote plus remote MCP endpoint, see Self-hosting above) are implemented and tested. Still out of scope, and coming later:

  • More mining readers: clanker setup already reads cwd out of Codex session logs to discover and register projects, but clanker mine itself still only extracts records from Claude Code transcripts. A Codex reader, and eventually Cursor, best-effort, is meant to slot in behind the same reader/extractor interfaces without changing clanker mine or the CLI.
  • Hosted, multi-tenant service: someone else's clanker serve running your vault for you, with accounts, billing and TLS handled for you. The server code for that already exists and is self-hostable today; only the multi-tenant operation of it is not built, and is the natural paid tier.

The on-disk format and this CLI's commands are meant to stay stable through all of that: a vault you start today should keep working unmodified once those layers land. The project is MIT licensed.