Skip to content

[FEATURE] A CLI on par with the MCP server, usable without it #1553

Description

@llucax

First, thanks for Basic Memory. I've been testing it for a week or two, so I'm still experimenting rather than speaking from a lot of practical experience, and still working out whether it's the right tool for me.

Some context on where I'm coming from, because it shapes everything below. A lot of my experimenting has gone into progressive disclosure: structuring knowledge so a session loads a short index first and pulls detail only when a task actually needs it, with the goal of keeping the context window as small as I can. Basic Memory fits that model well on the storage side, since the notes are already small, linkable and human-readable. The friction I keep running into is on the access side, which is what this issue is about.

I'd like to propose a direction rather than a single fix: a bm CLI that can do everything the MCP server can and that works with the MCP server switched off, ideally including a supported watcher so the database stays in sync. I'm not asking you to drop or deprecate the MCP server. I'm asking for the CLI to become a complete first-class path, so an agent that already has a shell can use Basic Memory without paying for the MCP surface at all.

I've collected some measurements below. They're all against installed 0.23.2, which is also the latest release (2026-08-25).

Why it matters: the cost is fixed and paid up front

what tokens
server instructions 175
tool schemas (21 tools) 11,284
total 11,459

So you can reconcile your own number with mine: tokenized with tiktoken cl100k_base over json.dumps(tool) per tool using Python's default separators, summed. With compact separators the same schemas come to 9,479 tokens, 16.0% lower. Either way, that cost is present from the first token of every session, whether or not the session ever touches the knowledge base, and there's no progressive disclosure. On unreleased main the surface is larger than what I measured, since #1507 enables six POSIX tools by default.

This keeps getting designed and then un-built

That's a good part of why I'm filing one meta-issue instead of four narrow ones.

#683, "CLI access to Basic Memory via auto-starting server (Ollama pattern)", proposes close to what I'm describing: a bm CLI auto-starting a warm background server, CLI and MCP sharing one process and SQLite backend over a Unix socket or local HTTP, and optionally a single coarse MCP tool to shrink the prompt surface. It was closed as completed on 2026-09-08, and I can't find a closing PR, an implementation link, or a comment explaining it. If that was bookkeeping on an old backlog, that's completely fair and I'd just like to know. If it shipped somewhere and I'm looking in the wrong place, please point me at it.

Earlier there was something concrete. #559 merged a standalone basic-memory watch on 2026-02-13, explicitly working without the MCP server. Eight days later, commit 2cde8d2 removed watch.py (97 lines) and tests/cli/test_watch.py (278 lines), pushed directly with no PR and no linked issue, commit message "clean up cli commands". I couldn't find a rationale in the commit, the changelog, the release notes, or any later issue. I'm not reading intent into it. My point is only that the need keeps resurfacing.

There's a real tension here and I'd rather state it than hide it. #1440 says there was no reliable daemon reachability probe and that watch-status.json wasn't validated, and #1414 ended up resolved with always-inline indexing precisely because reachability couldn't be trusted. That's an argument for a supported sync path, and also a fair reason to be wary of a daemon. #959 documented the other half of it, that CLI-only indexing has no coordinator and users get pointed at bm reindex. Whether the answer is a standalone watcher or the shared warm server from #683 is an implementation detail to me.

A cheap win: outputSchemas that tell clients nothing

20 of the 21 tools declare an outputSchema. 19 of those are FastMCP auto-wrapped {"result": ...} carrying x-fastmcp-wrap-result: true, and 12 are the entirely uninformative {"result": {"anyOf": [object, string]}}. They account for 1,698 of the 11,284 schema tokens, 15% of the schema budget, in every session.

Then it's paid again at call time. Declaring an outputSchema is what obliges the server to emit structuredContent next to the serialized copy in content. On a default-format search_notes call the full result was 7,511 bytes and 3,790 with structuredContent removed, so 49.5% of it was the duplicate, and content[0].text and structuredContent.result were byte-identical at 3,574 characters each. To be precise, those are bytes on the wire. Whether a given client feeds both copies into the model's context varies by client and I haven't measured that.

Dropping or slimming the auto-wrapped schemas looks like the smallest change with the clearest payoff in this whole issue.

Query efficiency, which only means anything relative to a need

The ratio depends entirely on what you're trying to get, so here's one fixed need: list 20 activity records as permalink and title, same query on both paths.

path content bytes wire bytes
CLI plus jq -r 1,886 1,886
MCP default (text) 3,704 7,759
MCP output_format=json 12,678 26,853

Raw CLI JSON for the same query is 15,007 bytes, and a projection keeping full note content is 6,517, so the CLI number isn't "JSON happens to be small". It's that I got to choose what to keep.

Credit where it's due: 14 of the 15 tools with an output_format parameter already default to text, only build_context defaults to json, and the text presets are a genuine effort at compactness. My criticism isn't that they're bloated, it's that the caller doesn't get to choose. With the CLI and jq I can express any field subset a preset can express plus ones it can't, and jq -r drops the JSON syntax entirely. An MCP caller takes whichever preset the tool author picked.

There's one place where that costs capability, not just bytes: search_notes text output drops note content when there's no matched_chunk, so an agent that needs the content has to ask for JSON and pay for the full payload. The preset is smaller there partly because it gives you less, with no way to ask for more.

What the direction looks like in practice

I've deliberately not filed these separately. Each line could be its own issue, but they're only worth the noise if the general direction makes sense to you, so I'd rather hear that first and then split up whatever you want split.


PS on where to file this: your issue template config points questions and open-ended ideas at Discussions, but Discussions look to be turned off on the repo, so the link there doesn't go anywhere and I filed it here instead. CONTRIBUTING.md also invites an issue to discuss an approach, which is what this is. If you'd rather this lived somewhere else, or as a discussion once they're enabled, please move or convert it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions