Skip to content

afaraha8403/mental

v0.14.0MIT

Never reconstruct where you left off. Local-first continuity for you and your coding agents — resume, decisions, and what's still in the air. CLI, MCP, and Agent Skills for Cursor, Claude Code, Copilot, and Codex.

Git records what changed. Mental CLI records the rest: the resume, the decision git cannot explain, and what’s still in the air. Your agents write it for you. You type mental when you want the pulse.

$ mental
🧠 Ship the pointer, not the dump — open loops: none
Against PLAN.md

Now     Resolver landed  (today)
Git     main (dirty)
        feat: UUID bindings survive a repo move
Hops    2
Needs eyes
  [verify] Resolver tests not reviewed
In the air
  [direction] Tom said ship the pointer
Later
  [thread] Come back to MCP
Unsettled
  [open] Heartbeat only, no standing TUI
Settled
  UUID bindings survive a repo move

One shot. Then exit. Not a menu. Not a todo app. Optional mental dashboard opens a localhost page over the same files.

Quick start

PowerShell, cmd.exe, Windows Terminal, Git Bash, macOS, and Linux:

npm i -g @balacode/mental
mental install
mental doctor

Then cd your-repo and type mental. npm owns the executable on every platform; mental install copies the agent skill/rule and creates the local data skeleton. Strict PowerShell policy: use npm.cmd / mental.cmd.

Upgrading from Mental 0.8.1 or older on Windows? Run mental-repair.cmd once after npm i -g; it quarantines only fingerprinted Mental-owned launchers that can shadow npm. Journals stay. Upgrade.

After install, agents journal, decide, and record residue while you work. You do not keep a second journal.

The unscoped npm package mental is a different project. Install @balacode/mental. The binary is mental.

Paste this into your agent

Works in Cursor, Claude Code, Copilot, Codex, and anything that can install a plugin or run a shell:

Install Mental CLI with npm. Do not clone the GitHub repo to install. Do not install from a git clone or plugin cache. Never run a .mjs file — Windows will ask what to open it with.

Fresh install (PowerShell, cmd, Windows Terminal, Git Bash, macOS, Linux):
  npm i -g @balacode/mental
  mental install
  mental doctor

Existing Windows install from Mental 0.8.1 or older (one-time migration):
  npm i -g @balacode/mental
  mental-repair.cmd
  mental install
  mental doctor
  (If PowerShell blocks scripts, use npm.cmd and mental.cmd explicitly.)

Mental CLI is a local-first continuity layer. Git records what changed; Mental records where we left off, why a decision was made, and what is still in the air. After install, you write it on my behalf — I do not journal by hand.

The repo is an Agent Plugins 1.0.0 package (https://agent-plugins.org/specification): plugin.json at the repo root, skills-only. Hosts load skills/mental-setup (install the CLI). The full procedure lives in skill/mental and is copied by `mental install` — not plugin-discovered. Native plugin does not start MCP. Do not start a plugin MCP server.

If this client has a native plugin install, use only that host's flow (do not run other hosts' `/plugin`, `copilot plugin`, or Command Palette steps from this session). npm owns the executable; `mental install` only refreshes the copied skill/rule/config. Run the fresh-install block, or the Windows migration block for an existing 0.8.1-or-older install.

The plugin is discovery. npm is the source of truth for the executable; the install command is the source of truth for the copied procedure. After doctor, re-run `mental doctor --json`. If anything is not ok that `--fix` can repair, run `mental doctor --fix --json` once (home skills/rules + git excludes only — never `--project` or optionals). Then tell me remaining checks. Follow the Mental skill copied by install — not the plugin bootstrap.

Missing Mental must not block my coding task (fail open): continue the task, then tell me to run the fresh-install block. Never execute the package's .mjs file directly.

After doctor, ask whether I want optional hooks or time tracking, and whether MCP is needed for this client. Give a one-liner for each, then wait — never run `mental option … on` until I say yes this turn.

- hooks: session-start snippets so a new chat loads Mental status (default off)
- MCP: register `mental serve` for tool-only agents that cannot shell the CLI (skip if this client can run `mental`)
- time tracking: optional automated project record — wall/billable, private + customer-ready descriptions, dated client export (default off)

Plugin install for each host (you, not the agent paste): docs/install.md.

Releasing this repo

package.json version is source of truth. Bump with node scripts/bump-version.mjs X.Y.Z, then --check. Tag only vX.Y.Z. Watch the Release workflow. The release is not done until:

npm view @balacode/mental version

equals that package.json string (no v). Agent rule: .cursor/rules/release.mdc.

Highlights

  • Agents are the scribe. After install, a skill + tiny always-on rule tell your coding agents to call mental … --json. Not every chat turn. Not a hidden hook. The plugin is discovery only (skills/mental-setup); the procedure is copied by mental install.
  • A pulse, not a dump. mental / heartbeat --json is resume + last outcome + git + residue + open decisions. 51 ms on a fresh process.
  • Markdown is the source of truth. OKF files in ~/.mental. SQLite is a derived cache. Deleting the db loses nothing.
  • Identity survives a move. UUID in bindings.json, not the folder path. Two clones of the same origin share one brain until you split.
  • Fail open. Private by default. Missing Mental CLI must not block coding. Never commit the store. Never write secrets.
  • Hours are optional. Default off. Agents generate private + customer-ready descriptions, clock wall/billable, and refresh the record at task boundaries. Genuine ambiguity uses one renderer-safe single-select question; otherwise capture stays automatic. --new runs another clock; dated client exports omit private detail. Track.

Who writes

YouYour agents
Type mental for the pulseJournal at a real task boundary
Ask “where did we leave off?”Record a decision that constrains the future
Install onceRecord residue the moment it surfaces
Read the receiptRe-pulse when another agent may have written

You will see this at the end of a turn that used Mental CLI:

🧠 **Mental**
- 📓 **Journal** › *recorded* › Resolver landed
- 🚦 **Attention** › *recorded* › Tom said ship

Same CLI if you ever type it yourself. Same files.

Why this exists

A new agent, another repo, Monday morning — someone reconstructs intent from chat and git log. That reconstruction is the tax. It is what developers feel as mental fry: verifying what the last agent did, deciding what the next one may touch, and holding residue across hops. Mental CLI removes it.

You already haveMental CLI adds
Git historyExact resume line
PLAN.md / issuesDecisions git cannot explain
Chat (gone next session)Attention residue, written down (capped at 7)

The last two years measured the tax. Experienced developers using Cursor believed they were 20% faster and were 19% slower (METR 2025). Productivity ratings held while flow and cognitive load eroded (Vella and Blincoe 2026). AI users switched windows more over two years — 74% did not notice (ICSE 2026). mental is the cue that hop needs.

Citations and what we do not claim: docs/research.md.

Numbers

Measured. Reproducible. npm test · npm run bench

0runtime npm dependenciesNode >=22.13
532automated testsidentity, search, install, MCP, optional track
51 msmental heartbeat --jsonp50, fresh process
11 mssame pulse in-processMCP after mental serve
46 mssearch over 2,000 notes1.2 ms in-process

Host and method: docs/benchmarks.md.

FAQ

Do I have to write the journal myself? No. Agents write it on your behalf. I type mental — you type mental when you want the pulse. Who writes.

Is this Mem0 / chat memory / a vector store? No. Mental CLI is project continuity, not conversation memory. Markdown files are the source of truth. No embeddings as SoT. No cloud.

Does it replace git, issues, or PLAN.md? No. Git still records what changed. --against PLAN.md points at the plan. Mental holds the small amount those systems cannot see.

Will it auto-journal every chat turn? No. Task boundaries, real decisions, residue in the air. Hooks stay off until you run mental hooks on.

Park, handoff, pulse — when? park encodes an interruption mid-hop. handoff is a planned close (journal + heartbeat). pulse is a compact cross-project overview. The cheap mid-chat reload is still mental / heartbeat --json.

How do I upgrade? Run npm i -g @balacode/mental, mental install, then mental doctor. Existing Windows installs from Mental 0.8.1 or older run mental-repair.cmd once after npm updates. Journals stay. The search index rebuilds on the next search. Skill copies refresh; the host plugin is a second channel — update it if doctor says it is behind. From a git checkout: npm run mental -- install. Upgrade.

What if mental is not installed? Agents continue the coding task and mention the three-command install block. They never execute a .mjs file directly. Fail open.

Where does data live? ~/.mental (never commit). Project ./.mental only after mental local. Uninstall does not delete OKF unless you type DELETE. Identity · Privacy

Laptop and desktop? mental backup --out ~/mental-backup on one machine, copy the directory, then mental restore --from ~/mental-backup on the other. Add --dry-run first to see which projects would be adopted or merged, how many files would land and how many of yours are newer and stay; it writes nothing. Restore will not overwrite newer work already on this PC. Do not Syncthing or Dropbox ~/.mental. --replace --confirm REPLACE is disaster-only.

Does Mental CLI track my hours? Only if you turn it on (mental option track on). Agents automatically record private and customer-ready descriptions, wall time, and billable time (wall by default). If input is genuinely needed, they use a plain-text draft with short single-select choices that maps to native host question renderers and falls back to numbered text. Export produces dated customer rows with work descriptions and hours; it never reconstructs missing time from git. Track.

Docs

Why Mental CLIContract, non-goals, architecture
The researchVerification load, supervisory work, 2024–2026 citations
Install Mental CLInpm, plugins, clone, upgrade, doctor, uninstall
DashboardRead-only localhost page over the same files
Host UIsClaude Code mod and the Cursor sidebar
Decision modelsOptional model assist (option decide; option jev is an alias)
Optional time trackingSit-down clock; what hours can and cannot do
Mental CLI referenceCommands, flags, exit codes
Mental CLI for agents--json, skill, MCP, receipts
Mental CLI identityUUID, remap / split / local
Mental CLI benchmarksp50 / p95 and how to reproduce
SkillThe procedure agents load
SpecFull product spec

Privacy

What leaves your machine

SurfaceLeaves?What is sentHow to turn it off
Core CLI (journal, search, why, heartbeat without a model)NoNothing—
Skill and ruleNoNothing—
Update checkPackage name onlynpm view of @balacode/mental when the cache is stale, including on --jsonMENTAL_SKIP_UPDATE_CHECK=1
MCPNostdio on this machinemental option mcp off
DashboardNoLoopback 127.0.0.1, GET and HEAD onlyStop mental dashboard
Decision modelsRedacted text, only with a keyThe configured providermental option decide off
HooksNoNothingmental option hooks off
Time trackingNoLocal sqlite, never gitmental option track off

There is no account, no telemetry, and no Mental server. API keys live in ~/.mental/config.json. On macOS and Linux that file is mode 0600. On Windows that mode is a no-op, so Mental also asks icacls for an owner-only ACL when it can. mental doctor --json includes a network list of these rows.

  • Default store: ~/.mental/ (never commit)
  • Project .mental/ is opt-in and must be gitignored (mental doctor --fix-ignore). Agents must not edit .gitignore
  • Writes redact obvious credentials locally before they hit disk ([REDACTED:kind]). --no-redact stores the text and says so. mental doctor --fix rewrites files that still match
  • mental uninstall does not delete OKF unless you type DELETE

Optional: mental install --mcp · mental hooks on · mental option track on · mental option decide key <KEY> — default off. Skill + rule are the contract. Hours never go in git. Track.

Decision models (optional)

Mental can use a fast, cheap decision model as a typed judge: yes/no (probability), choice and score, each with confidence. It never needs one. Pick a provider:

ProviderIdNotes
TypeSafe Jevtypesafe (default)System One API
OpenAI DecisionsopenaiPOST /v1/decisions, model gpt-6-luna (beta)
Cloudflare Clefcloudflareneeds your account id; model clef or clef-flash
Your own endpointcustomTypeSafe-shaped API, needs a URL

With a key it can recover a zero-hit mental search, hint "similar to existing" before a write, suggest links on mental show, and propose them with mental relink (typed: supports, supersedes, contradicts, depends_on). mental retag proposes topics for untagged files, mental brief orders residue by relevance, mental search --rank re-orders hits, and mental extract turns meeting notes into proposed actions and decisions. Writes also get advisory guards (data.guard: credential-looking text, a vague resume line, a decision that belongs in decide), and show flags text that instructs an agent. It fails open and only relink --apply, retag --apply and extract --apply write, high-confidence results only. Notes and decisions that get overwritten can be retired with mental supersede <path> --by <newer> or mental obsolete <path> (no model needed): the file is kept, only its status changes, and it drops out of the heartbeat and ranks last in search.

Keys are read only from ~/.mental/config.json (mode 0600), never from environment variables, and are never printed or sent over MCP:

mental option decide key <KEY>                         # key for the active provider
mental option decide key <KEY> --provider openai       # store another provider's key
mental option decide provider openai                   # choose the active provider
mental option decide account <ID> --provider cloudflare
mental option decide model clef-flash --provider cloudflare
mental option decide fallback cloudflare               # used when the active one fails (off to clear)
mental option decide personal off                      # never send personal-slice notes (default: allowed, secrets redacted)
mental option decide off                               # mute (also silences the reminder)
mental option decide budget 200000                     # optional cap on input tokens per day (budget off to clear)

mental option jev … still works as an alias, and an older jev config key migrates to the TypeSafe provider automatically. Status (mental option decide) shows the provider, which providers are configured, and today's requests and tokens.

In mental doctor. With a key, plain mental doctor also runs content checks, all warn-only (exit code unchanged): jev-stale (open residue that looks resolved or obsolete), jev-decisions (decisions that may contradict each other), jev-handoff (latest journal Resume: line missing or vague), jev-untagged (suggested topic per untagged file; never written), jev-secrets (files that may hold credentials; paths only, and values are redacted before anything is sent). Personal-slice notes are included unless you turn them off with option decide personal off. mental doctor --offline skips them; spend counts toward the daily budget.

Spend is tracked locally in jev-usage.json (counts only, no content) and is shared across providers. Requests are split to stay under each provider's limits, and cached answers are dropped when the model version changes.

Without a key, heartbeat and a zero-hit search occasionally (at most every 3 days) tell the agent a decision model is available so it can mention it. MENTAL_NO_HINTS=1 silences that.


npm: @balacode/mental · repo: afaraha8403/mental · license: MIT