GhostPaw

Your agent keeps its state in markdown files.

MEMORY.md, TODO.md, USER.md, SOUL.md. They grow every session, nobody prunes them, and one wrong line steers every run after it.

GhostPaw is seven small Node.js libraries, one for each of those files and for the skills, inbox and chats around them. Each keeps its part of the state as SQLite records inside your agent's own process, so you can read, correct and delete what the agent knows while it runs without you.

See all seven How they fit together

Free, MIT licence, Node.js 24 or newer. All seven have zero runtime dependencies. No account and no service to run.

A wolf head in profile drawn in thin cyan light lines, dissolving into violet sparks on black.

0runtime dependenciesin all seven packages

One library for each file your agent keeps

Each row names the file it takes over, what it gives an agent that runs with nobody watching, and the one command that installs it.

  1. Replaces MEMORY.md

    codex 0.3.2

    Beliefs instead of a memory file

    MEMORY.md stops being a junk drawer: every belief carries its source and certainty, stale ones are flagged when read, and a wrong fact gets corrected with its lineage kept.

    One record holds:

    • claim
    • source: explicit, observed or inferred
    • certainty and evidence count
    • freshness
    • lineage of corrections
  2. Replaces TODO.md

    questlog 0.6.2

    Quests instead of a to-do list

    An agent that said it was done has to write down what came of it, and a blocked quest stays blocked until the one before it succeeds.

    One record holds:

    • title and objective
    • dueAt or a scheduled window
    • unlocks that block other quests
    • outcome text on finish
    • repeat rule (RRULE)
  3. Replaces USER.md

    affinity 0.3.0

    Contacts instead of a user note

    The people your agent deals with, with their accounts, a journal of what happened, the promises made and the dates that matter, plus a radar of who is drifting out of touch.

    One record holds:

    • contact and identities (email, phone, account)
    • social link: rank, trust, cadence
    • ties such as works_at
    • journal entries as evidence
    • date anchors such as birthdays
  4. Replaces SOUL.md

    souls 0.3.0

    An identity that changes with evidence

    Character that moves only on evidence: refinements wait for level-up, and any of them can be rolled back.

    One record holds:

    • essence
    • traits with evidence
    • level-up consolidation
    • full rollback
  5. Replaces skills/

    grimoire 0.3.0

    Procedures that get better and keep their history

    Procedures stay SKILL.md files, each verified improvement is a git commit, and a health check names stale, dormant and oversized skills.

    One record holds:

    • spell: a SKILL.md file
    • seal: a git commit per verified improvement
    • tier from seal count
    • notes awaiting distillation
    • catalogue health snapshot
  6. Replaces inbox/

    email 0.4.1

    A mailbox the agent can search offline

    Your agent can read and search the mailbox. Whether it can also send is a separate tool, and you decide.

    One record holds:

    • account with IMAP and SMTP config
    • folder with sync state
    • message headers, flags, labels
    • body and attachments
    • thread tree
  7. Replaces chat log

    telegram 0.6.2

    Every Telegram update kept before your handler runs

    Every update lands in SQLite before your handler runs, edits keep the old text, and the agent's tools only plan until you switch execution on.

    One record holds:

    • message mirror with edit history
    • reply chains
    • FTS5 search with diacritic folding
    • file bytes as BLOBs, stored once per SHA-256 hash
    • plan-first agent tools

How they fit together

The packages never import each other. Your agent's code carries data from one to the next, and each keeps its own records, in its own tables.

Here is one afternoon of an agent that runs a small renewal desk on its own.

  1. telegram

    Lena posts “Invoice 4471 is paid” in the Renewal desk group, and telegram has the row before your handler sees it.

  2. affinity

    Your handler looks her up by Telegram account and adds the exchange to her journal.

  3. codex

    The agent writes “invoice 4471 is paid” as an explicit belief. Yesterday's belief said it was overdue. That one is superseded, not deleted, so you can still see what the agent thought before and why it changed.

  4. questlog

    The quest “Chase invoice 4471” closes only with a written outcome: paid, confirmed by Lena in the group.

  5. email

    It finds the invoice thread in the cached inbox with mail_search and labels it paid with mail_organize. A reply to the vendor would need mail_compose, which this agent was never given.

  6. grimoire

    It followed the steps in a SKILL.md for closing a paid invoice. Last time the receipt went to the wrong folder, and that note is still attached. When a better version proves itself, it is sealed as a git commit you can diff and roll back.

  7. souls

    Weeks of runs like this one pile up evidence for a trait: confirm payment with a person before closing a quest. The essence only changes at level-up, and you can roll the change back.

What the afternoon left on disk

~/.ghostpaw/

  • telegram.dbLena's message, edit kept
  • affinity.dbjournal entry for Lena
  • codex.dbbelief superseded, lineage kept
  • questlog.dbquest done, outcome written
  • email.dbthread labelled paid
  • grimoire/note on a SKILL.md, then a seal
  • souls.dbevidence for one trait

An illustration of one way to wire them, not a recorded run. Each library's own page replays a real run against its current release.

What all seven share

Runtime
Node.js 24 or newer and its built-in node:sqlite. Zero runtime dependencies, MIT licence.
Ways in
A library import, an MCP server started with npx -y @ghostpaw/<name> mcp, a ghostpaw-<name> command line tool and an Agent Skill. To connect these tools to a model in your own code, chatoyant is a zero-dependency OCaml/TypeScript LLM SDK by the same author, with guides on structured outputs, JS LLM SDK bundle size and calling LLMs from OCaml.
Where state lives
A SQLite file you can open. The MCP servers default to ~/.ghostpaw/<name>.db; grimoire also keeps its SKILL.md files in a git folder.
Taking one
Install one package and ignore the rest. None of them needs another to work.

If an agent working alone worries you

Plenty of developers switch agent memory off, because unread memories pile up and old lines win arguments, and an agent that also sends mail, posts in groups and rewrites its own instructions while you sleep is a bigger worry than one that only remembers.

Here is what each package does about it.

  • Every record is a row in a SQLite file your own process opens. You can read and delete it with sqlite3.
  • codex flags a belief nobody confirms for 90 days as stale, and recall calls no model.
  • questlog's run_quest tool refuses to start a quest whose prerequisites are unmet, unless the call passes force.
  • email keeps reading and sending in separate tools. Leave mail_compose out and the agent cannot send.
  • telegram's send and moderation tools return plans until you switch execution on.
  • souls and grimoire keep every change to identity and skills as history you can roll back.

All seven, side by side

Four paw prints in light walking up and to the right, the oldest fading violet, the newest bright cyan.
The seven GhostPaw packages and what we measured
PackageTakes overVersionRuntime depsTestsgzipImport
@ghostpaw/codexMEMORY.md0.3.2038031.5 KB2.5 ms
@ghostpaw/questlogTODO.md0.6.2035242.1 KB3.7 ms
@ghostpaw/affinityUSER.md0.3.0045956.1 KB4.8 ms
@ghostpaw/soulsSOUL.md0.3.0053231.4 KB2.8 ms
@ghostpaw/grimoireskills/0.3.0087246.4 KB7.6 ms
@ghostpaw/emailinbox/0.4.1056347.8 KB10.4 ms
@ghostpaw/telegramchat log0.6.2088734.2 KB8.9 ms

Measured 2026-10-24 on the maintainer's machine with Node.js 24.14.0 against the version shown: tests from node --test at the release tag, size as gzip -9 of the published dist/index.js, import time as the median of 11 cold imports.