bantamkit-mcp 0.33.0 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +335 -447
- package/dist/cli.js +5 -4
- package/dist/eventlog.js +24 -1
- package/dist/hostinstall.d.ts +39 -7
- package/dist/hostinstall.js +105 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/memory/store.d.ts +47 -0
- package/dist/memory/store.js +67 -1
- package/dist/npminstall.d.ts +54 -0
- package/dist/npminstall.js +141 -0
- package/dist/selfupdate.d.ts +39 -38
- package/dist/selfupdate.js +62 -108
- package/package.json +21 -2
package/README.md
CHANGED
|
@@ -1,324 +1,239 @@
|
|
|
1
|
-
# bantamkit-mcp
|
|
2
|
-
|
|
3
|
-
The bantamkit MCP server as a pure-Node package: `npx bantamkit-mcp`, no Python, no
|
|
4
|
-
`uv`, no `pipx`, no interpreter bootstrap. It serves the same twelve tools, the same
|
|
5
|
-
`bantamkit_status` prompt and the same two resource templates as `runtime-py`'s server,
|
|
6
|
-
reads and writes the same memory store, and is checked against the Python server frame by
|
|
7
|
-
frame — 4500+ conformance cases, with every intentional difference written down as a
|
|
8
|
-
ruling. It installs **two** commands, not one — the server and `bantamkit-memory`, the
|
|
9
|
-
operator CLI for memory-store lifecycle; see *The second bin* below.
|
|
10
|
-
|
|
11
|
-
Every number on this page was measured on the machine that wrote it, with a command you
|
|
12
|
-
can rerun. Where something was not measured, it says so.
|
|
13
|
-
|
|
14
|
-
## Install and run
|
|
15
|
-
|
|
16
|
-
```jsonc
|
|
17
|
-
// .mcp.json — project scope
|
|
18
|
-
{
|
|
19
|
-
"mcpServers": {
|
|
20
|
-
"bantamkit": {
|
|
21
|
-
"command": "npx",
|
|
22
|
-
"args": ["-y", "bantamkit-mcp"]
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
That is the whole install. No `pip`, no venv, no `PYTHONPATH`. `runtime-ts/mcp.json.example`
|
|
29
|
-
in the repository is the annotated version, with the four forms and the two measured
|
|
30
|
-
questions that decide between them.
|
|
1
|
+
# bantamkit-mcp — memory MCP server for Claude Code, Cursor, VS Code Copilot and Claude Desktop
|
|
31
2
|
|
|
32
|
-
**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
3
|
+
**bantamkit-mcp** is a pure-Node **MCP server** that gives coding agents a per-person **memory**
|
|
4
|
+
store, JSON Schema validation and shift-work tools. Install it from **npm** with one `npx`
|
|
5
|
+
command, connect it to **Claude Code**, **Claude Desktop**, **Cursor** or **GitHub Copilot in VS
|
|
6
|
+
Code**, and every later launch starts **offline**. No Python, `pip`, `uv`, `pipx` or venv.
|
|
36
7
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
8
|
+
It serves the same twelve tools, `bantamkit_status` prompt and two resource templates as the
|
|
9
|
+
Python server on **PyPI** (`pip install "bantamkit[mcp]"`), and reads and writes the same memory
|
|
10
|
+
store. The two are compared frame by frame: 8,130 conformance cases on 2026-09-15, with every
|
|
11
|
+
intentional difference written down as a ruling.
|
|
40
12
|
|
|
41
|
-
|
|
13
|
+
## Contents
|
|
42
14
|
|
|
43
|
-
|
|
15
|
+
| Topic | What you'll find |
|
|
16
|
+
|---|---|
|
|
17
|
+
| [Install the MCP server](#install-the-mcp-server) | Two ways to launch it — pick one |
|
|
18
|
+
| [Install once, run offline (recommended)](#install-once-run-offline) | One command; later launches need no network |
|
|
19
|
+
| [Run with npx at every launch](#run-with-npx-at-every-launch) | The online form, and why it hangs offline |
|
|
20
|
+
| [Connect to a host](#connect-to-a-host) | The same five steps for every host |
|
|
21
|
+
| [Connect to Claude Code](#connect-to-claude-code) | `--install claude`, `claude mcp list`, `claude mcp remove` |
|
|
22
|
+
| [Connect to Claude Desktop](#connect-to-claude-desktop) | `claude_desktop_config.json` per OS |
|
|
23
|
+
| [Connect to Cursor](#connect-to-cursor) | `~/.cursor/mcp.json` |
|
|
24
|
+
| [Connect to VS Code (GitHub Copilot)](#connect-to-vs-code-github-copilot) | `mcp.json` with the `servers` key |
|
|
25
|
+
| [Connect other MCP clients](#connect-other-mcp-clients) | Any stdio host, and a GUI host's PATH |
|
|
26
|
+
| [Updating](#updating) | `--update`, the per-install table, then restart |
|
|
27
|
+
| [Troubleshooting](#troubleshooting) | Connection closed, timeouts, `ENOENT`, refusals, the wrong store |
|
|
28
|
+
| [Configuration](#configuration) | Every flag and environment variable, with its default |
|
|
29
|
+
| [Silent version float](#silent-version-float) | Why two machines run different builds, and `build_identity` |
|
|
30
|
+
| [The operator CLI: `bantamkit-memory`](#the-operator-cli-bantamkit-memory) | The second bin: status, lint, compact, archive, restore |
|
|
31
|
+
| [Memory stores are layered by default](#memory-stores-are-layered-by-default) | Why not to add `--store` by reflex |
|
|
32
|
+
| [The asset pack](#the-asset-pack) | What ships in `assets/` and how it is found |
|
|
33
|
+
| [Sharing a store with the Python server](#sharing-a-store-with-the-python-server) | Concurrent writes, and one hand-edit to avoid |
|
|
34
|
+
| [Development](#development) | Build, test, conformance |
|
|
35
|
+
| [Measurements and history](#measurements-and-history) | Where the measured numbers behind this page live |
|
|
36
|
+
|
|
37
|
+
## Install the MCP server
|
|
38
|
+
|
|
39
|
+
A host launches the server every session, so what matters is whether each launch needs the
|
|
40
|
+
network. Pick **one** of the two ways below. To just try it: `npx -y bantamkit-mcp --assets-root`.
|
|
41
|
+
|
|
42
|
+
### Install once, run offline
|
|
43
|
+
|
|
44
|
+
**Recommended.**
|
|
44
45
|
|
|
45
46
|
```bash
|
|
46
|
-
npx -y bantamkit-mcp --install claude
|
|
47
|
-
npx -y bantamkit-mcp --install claude-desktop # Claude Desktop
|
|
48
|
-
npx -y bantamkit-mcp --install copilot # GitHub Copilot in VS Code
|
|
49
|
-
npx -y bantamkit-mcp --install cursor # Cursor
|
|
47
|
+
npx -y bantamkit-mcp@latest --install claude # or claude-desktop, copilot, cursor
|
|
50
48
|
```
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
50
|
+
From 0.34.0 this runs `npm install --prefix ~/.bantamkit/mcp` once (Windows:
|
|
51
|
+
`%USERPROFILE%\.bantamkit\mcp`, not measured) and records
|
|
52
|
+
`<the node that ran it> ~/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js`, both absolute.
|
|
53
|
+
No later launch needs npx, the registry or your PATH. Measured from the published 0.34.0:
|
|
54
|
+
install exit 0 in 8.14 s; the recorded command then served 12 tools in 0.09 s with the network
|
|
55
|
+
cut.
|
|
56
|
+
|
|
57
|
+
- **`@latest` matters:** without it npx may reuse an older cached resolve.
|
|
58
|
+
- **It skips npm when the kept install already reports this version or a newer one.** It never
|
|
59
|
+
downgrades. If npm fails, no host file is read or written and no backup is taken.
|
|
60
|
+
- **Run from any other install** (`npm i -g`, `npm i --prefix`, a checkout), it records that
|
|
61
|
+
install's own `dist/cli.js` instead.
|
|
62
|
+
- **The recorded node is one version of node.** Switch away from it and re-run with `--force`.
|
|
63
|
+
- **Replacing an old `npx` entry needs `--force`** (Claude Code: `claude mcp remove` first).
|
|
64
|
+
- **Installing into another host while offline:** plain `npx -y` hangs before bantamkit starts.
|
|
65
|
+
Use `npx --offline -y bantamkit-mcp@0.34.0 --install <host>`, or the kept install's own CLI:
|
|
66
|
+
`<node> ~/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js --install <host>`.
|
|
67
|
+
|
|
68
|
+
To make the kept install by hand, install once, then register node and `cli.js` by absolute
|
|
69
|
+
path (`node -p process.execPath` prints the node path). `-s user` makes it available in every
|
|
70
|
+
project; drop it for this project only:
|
|
68
71
|
|
|
69
72
|
```bash
|
|
70
|
-
|
|
73
|
+
npm install --prefix ~/.bantamkit/mcp bantamkit-mcp@latest
|
|
74
|
+
claude mcp add bantamkit -s user -- "$(node -p process.execPath)" ~/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js
|
|
71
75
|
```
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows. Top-level key
|
|
75
|
-
`mcpServers`; each entry takes `command`, `args` and an optional `env`.
|
|
77
|
+
### Run with npx at every launch
|
|
76
78
|
|
|
77
79
|
```json
|
|
78
80
|
{"mcpServers": {"bantamkit": {"command": "npx", "args": ["-y", "bantamkit-mcp"]}}}
|
|
79
81
|
```
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`
|
|
83
|
+
One config line (in `.mcp.json` for project scope, or a host's user config) and no install — but it asks the registry on **every** launch. Offline it fails
|
|
84
|
+
silently: with a warm cache, `npx -y bantamkit-mcp`, `npx -y bantamkit-mcp@latest` and
|
|
85
|
+
`npx -y bantamkit-mcp@0.33.0` each hung to the 45 s bound with 0 bytes on stdout, and the host
|
|
86
|
+
reports only its own handshake timeout.
|
|
84
87
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
**Cursor** — `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` globally. Back
|
|
92
|
-
to `mcpServers`.
|
|
88
|
+
- **Pass `-y`.** stdin is the JSON-RPC channel, and an install prompt that read one frame would
|
|
89
|
+
look like a server that lost a request.
|
|
90
|
+
- **Pin the version** (`bantamkit-mcp@0.34.0`) or add `@latest`: npx caches what `latest`
|
|
91
|
+
resolved to. See [Silent version float](#silent-version-float).
|
|
92
|
+
- **`npx --offline -y bantamkit-mcp@<version>`** serves a warm cache without the registry (0.40 s
|
|
93
|
+
measured), and fails at once with `npm error code ENOTCACHED` on a cache that never saw it.
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
{"mcpServers": {"bantamkit": {"command": "npx", "args": ["-y", "bantamkit-mcp"]}}}
|
|
96
|
-
```
|
|
95
|
+
`runtime-ts/mcp.json.example` in the repository is the annotated version, with five forms.
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
JSON-RPC on its stdin and stdout. Nothing about this package is host-specific.
|
|
97
|
+
## Connect to a host
|
|
100
98
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
`--install <host>` (`claude`, `claude-desktop`, `copilot`, `cursor`) writes the entry. It never
|
|
100
|
+
prompts, so it behaves the same in a terminal, in CI and inside another agent. For the three
|
|
101
|
+
JSON hosts it backs the file up first as `<name>.backup-<date>`, keeps the file's permissions,
|
|
102
|
+
refuses a file that does not parse, and refuses an entry that differs unless you pass `--force`.
|
|
104
103
|
|
|
105
|
-
|
|
104
|
+
Each host below has the same steps: **1** command, **2** file, **3** entry, **4** confirm,
|
|
105
|
+
**5** undo or re-run. The entry's `command` and `args` depend on the install route:
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
from disk into a cache that has never seen it, and drives a real MCP handshake. On
|
|
109
|
-
node v25.2.1 / npm 11.6.2, macOS (darwin 25.5.0), Apple silicon:
|
|
110
|
-
|
|
111
|
-
| | cold cache | warm cache |
|
|
112
|
-
|---|---|---|
|
|
113
|
-
| wall to the first JSON-RPC frame | **3.90 s** and **5.09 s**, two runs | **1.14 s** and **1.11 s** |
|
|
114
|
-
| npm/npx bytes on stderr | 211 (an `npm notice` about npm itself) | 0 |
|
|
115
|
-
|
|
116
|
-
Both cold figures are reported rather than averaged, and the two in that column are two
|
|
117
|
-
runs from **one sitting on 2026-08-25** — the column is labelled "two runs" and one
|
|
118
|
-
execution cannot honestly fill it.
|
|
119
|
-
|
|
120
|
-
**The spread is bigger than a range would suggest, and it is the network.** Five cold
|
|
121
|
-
runs on that same day, same machine, same commit, measured **3.68 / 3.90 / 4.66 / 5.09 /
|
|
122
|
-
9.66 s**. An earlier revision of this table read "4.13 s and 7.36 s" and called a cold
|
|
123
|
-
start "worth about 4-7 s here"; three of those five runs fall outside that range, so the
|
|
124
|
-
range is dropped rather than re-fitted. What a reader should take from the cold column is
|
|
125
|
-
an ORDER OF MAGNITUDE — seconds, dominated by the registry round trip, worse on a slower
|
|
126
|
-
link — and not a number to compare a future run against. The warm figure is the one that
|
|
127
|
-
is a property of this package, and it is stable across every run above.
|
|
128
|
-
|
|
129
|
-
- **92 packages** installed (top-level under `node_modules`, scope-aware); **111**
|
|
130
|
-
`package.json` **under `node_modules`**, which is the count of packages actually
|
|
131
|
-
installed:
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
find "$BED/cold/cache/_npx/<hash>/node_modules" -type f -name package.json | wc -l # 111
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Counting from the `_npx/<hash>` directory instead gives **112**, and the extra file is
|
|
138
|
-
not a package: npx synthesises a `package.json` at that root holding the `file:` spec
|
|
139
|
-
and an `_npx.packages` array. The method is written down here because the 112 was read
|
|
140
|
-
once as a drift of one and it is not one — it is a different denominator. Reproduce
|
|
141
|
-
either with `node tools/conformance/npx-cold-start.mjs --keep`, which prints the scratch
|
|
142
|
-
path it leaves behind.
|
|
143
|
-
- **15.7 MB** of files under `$npm_config_cache/_npx/<hash>` (26 MB of allocated blocks by
|
|
144
|
-
`du`), **37.8 MB** for the whole cache including npm's content-addressable store (this
|
|
145
|
-
read 37.7 until 2026-08-25; all four cold runs that day printed 37.8).
|
|
146
|
-
- `bantamkit-mcp` itself is **0.9 MB** of that (1.2 MB allocated). The rest is
|
|
147
|
-
`@modelcontextprotocol/sdk@1.30.0`'s dependency tree, which pulls in `express`, `cors`,
|
|
148
|
-
`body-parser`, `ajv`, `eventsource`, `hono` and `express-rate-limit` — the SDK's HTTP
|
|
149
|
-
transport, none of which this stdio server uses. That is the SDK's shape, not a choice
|
|
150
|
-
this package makes; it declares exactly one runtime dependency.
|
|
151
|
-
- The tarball is **~266 KB**, 137 files: 50 in `dist/`, 84 in `assets/`, plus `LICENSE`,
|
|
152
|
-
`package.json` and this README. (The exact byte count moves whenever this file does;
|
|
153
|
-
the gate prints it, and `test/packaging.test.mjs` pins the file list.)
|
|
154
|
-
|
|
155
|
-
### Measured: what happens when the registry is not reachable
|
|
156
|
-
|
|
157
|
-
A cold `npx` start needs the network. Measured with the registry pointed at a closed port
|
|
158
|
-
and at a blackholed address, driving the same handshake:
|
|
159
|
-
|
|
160
|
-
| registry | seconds before `npx` gave up | bytes the client saw on stdout |
|
|
107
|
+
| Route | `command` | `args` |
|
|
161
108
|
|---|---|---|
|
|
162
|
-
|
|
|
163
|
-
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
**
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
109
|
+
| npm, install once | `/absolute/path/to/node` | `["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"]` |
|
|
110
|
+
| Python venv | `/absolute/path/to/env/bin/bantamkit-mcp` | `[]` |
|
|
111
|
+
| npx every launch | `npx` | `["-y", "bantamkit-mcp"]` |
|
|
112
|
+
|
|
113
|
+
A JSON file cannot expand `~`, so spell both paths out. To check a recorded command, run it in
|
|
114
|
+
a terminal: with nothing on stdin it prints `usage: bantamkit-mcp …` and exits 0.
|
|
115
|
+
|
|
116
|
+
### Connect to Claude Code
|
|
117
|
+
|
|
118
|
+
1. **Command:** `npx -y bantamkit-mcp@latest --install claude`
|
|
119
|
+
2. **File:** none edited directly — it runs `claude mcp add bantamkit -s user -- <command> <args>`
|
|
120
|
+
(user scope, every project). `~/.claude.json` is the host's file, and it holds state that is
|
|
121
|
+
not MCP configuration.
|
|
122
|
+
3. **Entry:** printed as `ran : claude mcp add bantamkit -s user -- <node> <cli.js>`.
|
|
123
|
+
4. **Confirm:** `claude mcp list` prints `bantamkit: <node> <cli.js> - ✔ Connected` (Claude Code
|
|
124
|
+
2.1.272; run it outside a project whose `.mcp.json` also names bantamkit, or it prints
|
|
125
|
+
`[Conflicting scopes]`). In a session, ask the agent to call `bantamkit_status`.
|
|
126
|
+
5. **Undo / re-run:** `--force` does not reach Claude Code, and a second add fails with
|
|
127
|
+
`MCP server bantamkit already exists in user config`. Remove first:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
claude mcp remove bantamkit -s user
|
|
131
|
+
npx -y bantamkit-mcp@latest --install claude
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Connect to Claude Desktop
|
|
135
|
+
|
|
136
|
+
1. **Command:** `npx -y bantamkit-mcp@latest --install claude-desktop`
|
|
137
|
+
2. **File:** macOS `~/Library/Application Support/Claude/claude_desktop_config.json` ·
|
|
138
|
+
Windows `%APPDATA%\Claude\claude_desktop_config.json` ·
|
|
139
|
+
Linux `~/.config/Claude/claude_desktop_config.json`
|
|
140
|
+
3. **Entry** (key `mcpServers`; each entry takes `command`, `args` and an optional `env`):
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{"mcpServers": {"bantamkit": {"command": "/absolute/path/to/node", "args": ["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"]}}}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
4. **Confirm:** it prints `installed bantamkit into claude-desktop` with file, key and command.
|
|
147
|
+
Fully quit and reopen Claude Desktop, then ask it to call `bantamkit_status`.
|
|
148
|
+
5. **Undo / re-run:** there is no uninstall flag — delete the `bantamkit` entry or restore
|
|
149
|
+
`claude_desktop_config.json.backup-<date>`. A matching re-run prints
|
|
150
|
+
`bantamkit is already installed in claude-desktop and matches`; a differing entry needs `--force`.
|
|
151
|
+
|
|
152
|
+
### Connect to Cursor
|
|
153
|
+
|
|
154
|
+
1. **Command:** `npx -y bantamkit-mcp@latest --install cursor`
|
|
155
|
+
2. **File:** `~/.cursor/mcp.json` on every OS (`%USERPROFILE%\.cursor\mcp.json` on Windows);
|
|
156
|
+
`.cursor/mcp.json` for one project, by hand.
|
|
157
|
+
3. **Entry** (key `mcpServers`):
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{"mcpServers": {"bantamkit": {"command": "/absolute/path/to/node", "args": ["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"]}}}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
4. **Confirm:** it prints `installed bantamkit into cursor` and `key : mcpServers`. Restart
|
|
164
|
+
Cursor and ask the agent to call `bantamkit_status`.
|
|
165
|
+
5. **Undo / re-run:** delete the entry or restore `mcp.json.backup-<date>`. To replace a
|
|
166
|
+
differing entry, such as an old `npx` one:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npx -y bantamkit-mcp@latest --install cursor --force
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Connect to VS Code (GitHub Copilot)
|
|
173
|
+
|
|
174
|
+
1. **Command:** `npx -y bantamkit-mcp@latest --install copilot`
|
|
175
|
+
2. **File:** macOS `~/Library/Application Support/Code/User/mcp.json` ·
|
|
176
|
+
Windows `%APPDATA%\Code\User\mcp.json` · Linux `~/.config/Code/User/mcp.json`;
|
|
177
|
+
`.vscode/mcp.json` for one workspace, or **MCP: Open User Configuration**, by hand.
|
|
178
|
+
3. **Entry** — the key is **`servers`**, not `mcpServers`, plus `"type": "stdio"`. This is the
|
|
179
|
+
detail that catches people out:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{"servers": {"bantamkit": {"type": "stdio", "command": "/absolute/path/to/node", "args": ["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"]}}}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
VS Code's own CLI can add an entry too (from VS Code's documentation, not measured here):
|
|
186
|
+
`code --add-mcp '{"name":"bantamkit","command":"npx","args":["-y","bantamkit-mcp"]}'`.
|
|
187
|
+
4. **Confirm:** it prints `installed bantamkit into copilot` and `key : servers`. Restart
|
|
188
|
+
VS Code and ask Copilot to call `bantamkit_status`.
|
|
189
|
+
5. **Undo / re-run:** delete the entry or restore `mcp.json.backup-<date>`; `--force` replaces
|
|
190
|
+
a differing entry.
|
|
191
|
+
|
|
192
|
+
### Connect other MCP clients
|
|
193
|
+
|
|
194
|
+
Anything that speaks MCP over stdio runs the same `command`/`args` and talks JSON-RPC on stdin
|
|
195
|
+
and stdout; nothing in this package is host-specific. Codex and a generic JSON config:
|
|
196
|
+
[docs/mcp.md → Client setup](https://github.com/Ink01101011/bantamkit/blob/main/docs/mcp.md#client-setup).
|
|
197
|
+
|
|
198
|
+
**A GUI-launched host does not read your shell rc.** If `node` and `npx` come from mise, nvm or
|
|
199
|
+
similar, they are not on its PATH (`/usr/bin:/bin:/usr/sbin:/sbin` on macOS). An `npx` entry then
|
|
200
|
+
fails with `ENOENT`, and a `.bin/bantamkit-mcp` shim exits 127 with
|
|
201
|
+
`env: node: No such file or directory`, because its first line is `#!/usr/bin/env node`. Name
|
|
202
|
+
node by absolute path, as `--install` does.
|
|
197
203
|
|
|
198
|
-
|
|
199
|
-
// absolute path to the npx you actually have
|
|
200
|
-
{ "command": "/Users/you/.local/share/mise/installs/node/latest/bin/npx",
|
|
201
|
-
"args": ["-y", "bantamkit-mcp@0.25.0"] }
|
|
202
|
-
```
|
|
204
|
+
## Updating
|
|
203
205
|
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
{ "command": "/usr/local/bin/bantamkit-mcp", "args": [] }
|
|
206
|
+
```bash
|
|
207
|
+
npx -y bantamkit-mcp@latest --update
|
|
207
208
|
```
|
|
208
209
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
The sh launcher is not obsolete. It guarantees things `npx` cannot, and this table is the
|
|
212
|
-
prep probe's, unsoftened.
|
|
213
|
-
|
|
214
|
-
| guarantee | `tools/bantamkit-mcp` | `npx bantamkit-mcp` |
|
|
215
|
-
|---|---|---|
|
|
216
|
-
| present in every checkout **and** every worktree | yes — it is a file in the tree | **gone.** Depends on the host's PATH, not on the project directory |
|
|
217
|
-
| runs *this* checkout's code | yes | **gone for developers too.** Testing a worktree needs an absolute `node <worktree>/dist/cli.js`, or the host silently runs the published build |
|
|
218
|
-
| code from the worktree, deps from the main checkout | yes (`PYTHONPATH` + `PYTHONSAFEPATH`) | **no Node analogue.** `NODE_PATH` is ignored by ESM and there is no `-P`. `npm link` and workspaces are a different failure surface, not the same one solved |
|
|
219
|
-
| stdin is the JSON-RPC channel | yes | yes, with `-y` |
|
|
220
|
-
| names the cause when dependencies are missing | yes | the analogous failure is *no network*, and it has no message at all — see the table above |
|
|
221
|
-
| starts without a network | yes | **no**, on a cold cache |
|
|
222
|
-
| `--which`, for diagnosing which endpoint answered | the flag exists | **not in the npx CLI** — but `tools/bantamkit-mcp-node --which` has it, see below |
|
|
223
|
-
| one config line, no clone, no venv | no | **yes.** This is the whole reason the package exists |
|
|
224
|
-
|
|
225
|
-
### `--which` is a launcher flag, not a package flag
|
|
226
|
-
|
|
227
|
-
This section previously read "`--which` is deleted, not ported" and said "there is no
|
|
228
|
-
Node `--which`, and none is planned". Both are now false, and the second was made false
|
|
229
|
-
inside this repository: `tools/bantamkit-mcp-node` ships `--which`, and
|
|
230
|
-
`runtime-ts/test/launcher.test.mjs` runs it — including on a checkout that has never been
|
|
231
|
-
built, which is the case the Python flag's `find_spec` was chosen for. It prints
|
|
232
|
-
`checkout=`, `deps_root=`, `runtime=node`, `node=`, `entry=` (suffixed `(missing)` when
|
|
233
|
-
`dist/` is absent) and `sdk=`.
|
|
234
|
-
|
|
235
|
-
What is genuinely not ported is `--which` **on the published package**, and the reason is
|
|
236
|
-
the line above it in the table: `npx bantamkit-mcp` does not run a checkout, so
|
|
237
|
-
`checkout=` and `source=` have nothing to report. The question a reader has about an npx
|
|
238
|
-
endpoint is not *where did this resolve* but *which build answered*, and that is
|
|
239
|
-
`build_identity` — a tool on the wire rather than a flag on a launcher, and what the next
|
|
240
|
-
section is about.
|
|
241
|
-
|
|
242
|
-
The old wording came from a real defect, which is now closed. `tools/bantamkit-mcp:47`
|
|
243
|
-
used to name `tools/mcpreach/mcpreach.py` as `--which`'s consumer and `docs/mcp.md` used
|
|
244
|
-
to document a five-value exit-code interface for that program (`0` REACHABLE, `1`
|
|
245
|
-
UNREACHABLE, `2` FOREIGN, `3` UNDECLARED, `4` NO_ENV). **That program has never existed** —
|
|
246
|
-
`git log --all --diff-filter=A -- '*mcpreach*'` is empty across every ref in this
|
|
247
|
-
repository, and `docs/eval.md` records the decision not to ship it, the half-built checker
|
|
248
|
-
having "never been seen to fire". Both citations were rewritten on 2026-08-24 to name what
|
|
249
|
-
actually runs, and `runtime-py/tests/test_doc_commands_gate.py` is now red if any fenced
|
|
250
|
-
shell block in the repository names a `tools/` program that is not in the tree.
|
|
251
|
-
|
|
252
|
-
## Silent version float, and the instrument for it
|
|
253
|
-
|
|
254
|
-
This is the one that will bite a team hardest.
|
|
255
|
-
|
|
256
|
-
`npx -y bantamkit-mcp` resolves the dist-tag `latest` and caches the result. Two people
|
|
257
|
-
with byte-identical `.mcp.json` files can be running different builds — one resolved last
|
|
258
|
-
week, one resolved this morning — and nothing in the config, the logs or the tool output
|
|
259
|
-
says so. The sh launcher could not do this: it ran the checkout you were standing in.
|
|
260
|
-
|
|
261
|
-
Call `build_identity`. Three fields answer it:
|
|
210
|
+
`--update` — `check the package index and update this install if it differs, then exit` — asks
|
|
211
|
+
the npm registry for `latest` and compares it with the installed version:
|
|
262
212
|
|
|
263
|
-
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
serving different data.
|
|
270
|
-
- **`code_digest`** / **`build_id`** — over `dist/**/*.js` on this side and `*.py` on the
|
|
271
|
-
other, so they are *required* to differ across runtimes and required to match across two
|
|
272
|
-
installs of the same version. `build_id` differing between two teammates on the same
|
|
273
|
-
version string is the float, caught.
|
|
274
|
-
|
|
275
|
-
The output carries a `cross_runtime` sentence saying in plain words which fields are
|
|
276
|
-
comparable. `git_commit` is refused rather than guessed: an installed npm tarball carries
|
|
277
|
-
no repository, and reading a checkout's HEAD would describe the tree rather than the bytes
|
|
278
|
-
that were imported (RB-P84).
|
|
279
|
-
|
|
280
|
-
**Pin the version in the config** if you want this to be a non-issue:
|
|
281
|
-
`"args": ["-y", "bantamkit-mcp@0.30.0"]`.
|
|
213
|
+
- **Same version:** prints both numbers and `up to date.`
|
|
214
|
+
- **Behind, on a registry install or a kept install from `--install` (0.34.0+):** runs the
|
|
215
|
+
matching row below and prints npm's output.
|
|
216
|
+
- **Behind, on any other shape** (a checkout, a linked tree, a local file, an npx cache with no
|
|
217
|
+
kept install): refuses with exit 1 and names your row. It will not write a registry install
|
|
218
|
+
into a tree you manage with `git`.
|
|
282
219
|
|
|
283
|
-
|
|
220
|
+
It is the only network access here — not at startup, not on `bantamkit_status`, not on any tool
|
|
221
|
+
— with a 10-second timeout, and being offline is a named refusal on stderr, never a traceback.
|
|
284
222
|
|
|
285
|
-
|
|
286
|
-
this is the thing that updates it, and there are five install shapes with five different
|
|
287
|
-
answers. Pick the row you are actually on — and note that **the running server keeps
|
|
288
|
-
serving the code it loaded at startup**, so every row ends with restarting it in the host.
|
|
289
|
-
|
|
290
|
-
> **AMENDED 2026-09-11 — there IS a `bantamkit-mcp --update` now, and the paragraph above is
|
|
291
|
-
> kept rather than rewritten because everything in it is still true of what the flag does.**
|
|
292
|
-
> `bantamkit-mcp --update` asks the npm registry for `latest` and compares it to the version
|
|
293
|
-
> that is installed. If they match it prints both numbers and `up to date.` and stops. If the
|
|
294
|
-
> index is ahead **and this is a registry install**, it runs the row below that applies to you
|
|
295
|
-
> and prints what npm said. If the index is ahead and this is any OTHER shape, **it refuses,
|
|
296
|
-
> exits 1, and names the row you are on** — it will not write a registry install into a tree
|
|
297
|
-
> you manage with `git`, and a command that exits 0 having changed nothing is worse than one
|
|
298
|
-
> that says no. Either way it ends by telling you to restart the server, for the reason the
|
|
299
|
-
> paragraph above gives: a successful update does not change the process that is answering
|
|
300
|
-
> you. The flag reaches the network and nothing else here does — not at startup, not on
|
|
301
|
-
> `bantamkit_status`, not on any tool — with a 10-second timeout, and being offline is a named
|
|
302
|
-
> refusal on stderr, never a traceback. The table below is still the reference for what to do
|
|
303
|
-
> by hand, and it is what `--update` prints back at you when it will not act.
|
|
304
|
-
|
|
305
|
-
| how it was installed | how to update |
|
|
223
|
+
| How it was installed | How to update |
|
|
306
224
|
|---|---|
|
|
307
|
-
| `npx -y bantamkit-mcp` in the host config |
|
|
225
|
+
| `npx -y bantamkit-mcp` in the host config | Nothing to update, but npx **caches the resolved version**: add `@latest` (or pin `@0.34.0`). `rm -rf ~/.npm/_npx` forces a clean resolve |
|
|
226
|
+
| `npx -y bantamkit-mcp --install <host>` from 0.34.0: a kept install at `~/.bantamkit/mcp` | `npx -y bantamkit-mcp@latest --update` patches it in place, or `npm i --prefix ~/.bantamkit/mcp bantamkit-mcp@latest`. The recorded paths do not change. Before 0.34.0, `--update` from an npx cache refuses instead |
|
|
308
227
|
| `npm i -g bantamkit-mcp` | `npm i -g bantamkit-mcp@latest` |
|
|
309
228
|
| `npm i --prefix <dir> bantamkit-mcp` | `npm i --prefix <dir> bantamkit-mcp@latest` |
|
|
310
229
|
| PyPI (`pip install "bantamkit[mcp]"`) | `pip install -U "bantamkit[mcp]"` · pipx: `pipx upgrade bantamkit` · uv: `uv tool upgrade bantamkit` |
|
|
311
|
-
| a checkout, via `tools/bantamkit-mcp-node` | `git pull && npm ci --prefix runtime-ts && npm run build --prefix runtime-ts` —
|
|
230
|
+
| a checkout, via `tools/bantamkit-mcp-node` | `git pull && npm ci --prefix runtime-ts && npm run build --prefix runtime-ts` — no registry, and `runtime-ts/dist/` is build output, so a pull alone changes nothing |
|
|
312
231
|
|
|
313
|
-
**Then restart the server in your host
|
|
314
|
-
Claude Code
|
|
315
|
-
Measured 2026-09-07 (served-tools: dated — the surface was eleven then; 0.30.0's
|
|
316
|
-
`memory_dream` and `repo_map` made it thirteen): a checkout whose `dist/` had just been
|
|
317
|
-
rebuilt at 0.30.0 kept answering `version 0.29.1, serving 11 tools` until the host
|
|
318
|
-
reconnected — the disk was current and the process was not.
|
|
232
|
+
**Then restart the server in your host** — a running server keeps serving the code it loaded at
|
|
233
|
+
startup. In Claude Code: `/mcp` → reconnect. In Claude Desktop: a full restart of the app.
|
|
319
234
|
|
|
320
|
-
**Verify with `bantamkit_status`, not
|
|
321
|
-
|
|
235
|
+
**Verify with `bantamkit_status`, not the install log.** It reports the version and the
|
|
236
|
+
`build_id` of *the code that is answering you*:
|
|
322
237
|
|
|
323
238
|
```
|
|
324
239
|
bantamkit Active 🟢
|
|
@@ -326,171 +241,138 @@ version 0.30.0, build sha256:4441619d…
|
|
|
326
241
|
serving 12 tools, 1 prompt, 2 resource templates
|
|
327
242
|
```
|
|
328
243
|
|
|
329
|
-
A version
|
|
330
|
-
not a process.
|
|
331
|
-
|
|
332
|
-
### The failure this table exists for
|
|
333
|
-
|
|
334
|
-
Measured on a real machine, 2026-09-07: a Claude Desktop entry pointed at
|
|
335
|
-
`~/.local/share/bantamkit-mcp/node_modules/.bin/bantamkit-mcp`, which was **0.25.0** — five
|
|
336
|
-
releases stale — and its `package.json` declared
|
|
337
|
-
|
|
338
|
-
```json
|
|
339
|
-
"bantamkit-mcp": "file:/private/tmp/.../scratchpad/bantamkit-mcp-0.25.0.tgz"
|
|
340
|
-
```
|
|
244
|
+
A version that moved and a `build_id` that did not means you are reading a config, not a process.
|
|
341
245
|
|
|
342
|
-
a
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
which restores a normal semver dependency and leaves the host config's path valid.
|
|
246
|
+
**Tested a build from a local `.tgz`? Install over it from the registry afterwards**
|
|
247
|
+
(`npm i --prefix <dir> bantamkit-mcp@latest`). Otherwise that machine stays pinned to a `file:`
|
|
248
|
+
dependency in a temp directory that will be deleted, and `npm update` cannot help.
|
|
346
249
|
|
|
347
|
-
|
|
348
|
-
afterwards**, or that machine is pinned to a file that will be deleted.
|
|
250
|
+
## Troubleshooting
|
|
349
251
|
|
|
350
|
-
|
|
252
|
+
| Symptom | Fix |
|
|
253
|
+
|---|---|
|
|
254
|
+
| Connection closed at startup (`CONNECTION_CLOSED`) | Builds before 0.32.1 crashed when a GUI host started them with cwd `/`. Update, then restart the server |
|
|
255
|
+
| The host times out; the server never answers | The entry uses `npx` with a registry spec and the network is down. Use [Install once, run offline](#install-once-run-offline) |
|
|
256
|
+
| `ENOENT` from the host, or `env: node: No such file or directory` | A GUI host does not have your shell's PATH. `--install` records node by absolute path; see [Connect other MCP clients](#connect-other-mcp-clients) |
|
|
257
|
+
| `npm error code ENOTCACHED` | `npx --offline` on a cache that has never seen that spec. Run it once online, or use the kept install |
|
|
258
|
+
| `already has a bantamkit entry with different settings … re-run with --force to replace it` | Re-run with `--force`; the old file is kept as `.backup-<date>` |
|
|
259
|
+
| `MCP server bantamkit already exists in user config` | `claude mcp remove bantamkit -s user`, then install again |
|
|
260
|
+
| The server stopped launching after a node change | `npx -y bantamkit-mcp@latest --install <host> --force` with the node you have now |
|
|
261
|
+
| Two machines with one config run different builds | [Silent version float](#silent-version-float): compare `build_id` |
|
|
262
|
+
| `bantamkit_status` still shows the old version after an update | The host has not reconnected; restart the server |
|
|
263
|
+
| Recall finds nothing, or the wrong store | Set `BANTAMKIT_MEMORY_DIR`; the reply names the store it searched |
|
|
264
|
+
| `malformed fact file …` | A hand-edited fact has a bare non-string field; see [Sharing a store](#sharing-a-store-with-the-python-server) |
|
|
265
|
+
| `AssetNotFound: no assets directory found; set BANTAMKIT_ASSETS` | See [The asset pack](#the-asset-pack) |
|
|
266
|
+
|
|
267
|
+
## Configuration
|
|
268
|
+
|
|
269
|
+
Flags go in the entry's `args`; environment variables in its `env` block (or
|
|
270
|
+
`claude mcp add -e NAME=value`). Both runtimes print the same `--help`.
|
|
271
|
+
|
|
272
|
+
| Setting | What it does | Default | Example |
|
|
273
|
+
|---|---|---|---|
|
|
274
|
+
| `BANTAMKIT_MEMORY_DIR` | Pins the store to one absolute path; a missing or relative path refuses at startup | unset: nearest existing `.bantamkit/memory` at or above the start directory | `"env": {"BANTAMKIT_MEMORY_DIR": "/abs/project/.bantamkit/memory"}` |
|
|
275
|
+
| `--store STORE` | One store, layering off; outranks `BANTAMKIT_MEMORY_DIR` | off (layered) | `"--store", "/abs/store"` |
|
|
276
|
+
| `--start START` | Where store discovery starts; not with `--store` | cwd | `"--start", "/abs/project"` |
|
|
277
|
+
| Layered memory | Recall reads the project store, stores granted in `.bantamkit/config.yaml`, and `~/.bantamkit/memory`; saves go to the project store | on | [Memory stores are layered by default](#memory-stores-are-layered-by-default) |
|
|
278
|
+
| `--k K` | Default recall budget | `3` | `"--k", "5"` |
|
|
279
|
+
| `--index-budget BYTES` | Memory index byte budget | `24000` | `"--index-budget", "32000"` |
|
|
280
|
+
| `BANTAMKIT_EVENT_LOG` | Logs tool outcomes as JSONL | off; `on` → `<store>/events/mcp.jsonl`; other values are a path | `"env": {"BANTAMKIT_EVENT_LOG": "on"}` |
|
|
281
|
+
| `BANTAMKIT_ASSETS` | Your own asset pack (skills, rubrics, schemas) | the pack inside the package | `"env": {"BANTAMKIT_ASSETS": "/abs/my-assets"}` |
|
|
282
|
+
| `BANTAMKIT_HOST_LOG_ROOT` | Where `--mcp-report` finds the host's MCP logs | macOS `~/Library/Caches/claude-cli-nodejs`; elsewhere unset | `BANTAMKIT_HOST_LOG_ROOT=/abs/logs bantamkit-mcp --mcp-report` |
|
|
283
|
+
| `BANTAMKIT_PRICES` | Price table for the token ledger | `pricing/default.json` in the asset pack | `"env": {"BANTAMKIT_PRICES": "/abs/prices.json"}` |
|
|
284
|
+
|
|
285
|
+
One-shot commands that print and exit: `--install {claude,claude-desktop,copilot,cursor}` (with
|
|
286
|
+
`--force`), `--update`, `--assets-root`, `--mcp-report`, `--statusline`, `-h`. Typing
|
|
287
|
+
`bantamkit-mcp` at a terminal with nothing after it prints the help and exits 0; a host launch
|
|
288
|
+
down a pipe still starts the server, and `bantamkit-mcp --store /tmp/x` at a terminal still
|
|
289
|
+
serves. `--which` belongs to the checkout launchers `tools/bantamkit-mcp` and
|
|
290
|
+
`tools/bantamkit-mcp-node`, not to this package: an npx install runs no checkout, so ask
|
|
291
|
+
`build_identity` which build answered instead.
|
|
292
|
+
|
|
293
|
+
## Silent version float
|
|
294
|
+
|
|
295
|
+
`npx -y bantamkit-mcp` resolves the dist-tag `latest` and caches the result. Two people with
|
|
296
|
+
byte-identical `.mcp.json` files can be running different builds — one resolved last week, one
|
|
297
|
+
this morning — and nothing in the config, the logs or the tool output says so. This is the one
|
|
298
|
+
that will bite a team hardest.
|
|
299
|
+
|
|
300
|
+
**Fix:** pin the version in the config (`"args": ["-y", "bantamkit-mcp@0.34.0"]`), or use the
|
|
301
|
+
kept install from `--install`, which serves the version in `~/.bantamkit/mcp` until someone runs
|
|
302
|
+
`--update`.
|
|
303
|
+
|
|
304
|
+
**Detect it:** call the `build_identity` tool. Three fields answer it:
|
|
351
305
|
|
|
352
|
-
`
|
|
353
|
-
and
|
|
306
|
+
- **`runtime`** — `"node"` here, absent on the Python server. Its *presence* is the
|
|
307
|
+
discriminator, and it is folded into `build_id` so the two lineages cannot collide.
|
|
308
|
+
- **`assets_digest`** — sha256 over every byte of the asset pack, computed identically in both
|
|
309
|
+
runtimes and verified equal (`sha256:eb79f9e3…` over 91 files from Python and from Node,
|
|
310
|
+
`node tools/conformance/run.mjs --all`, 2026-09-15). Two
|
|
311
|
+
machines disagreeing here are serving different data.
|
|
312
|
+
- **`code_digest`** / **`build_id`** — over `dist/**/*.js` here and `*.py` on the Python side, so
|
|
313
|
+
they must differ across runtimes and must match across two installs of one version. `build_id`
|
|
314
|
+
differing between two teammates on the same version string is the float, caught.
|
|
315
|
+
|
|
316
|
+
The output carries a `cross_runtime` sentence naming which fields are comparable. `git_commit` is
|
|
317
|
+
refused rather than guessed: an npm tarball carries no repository, and a checkout's HEAD would
|
|
318
|
+
describe the tree, not the bytes that were imported (RB-P84).
|
|
319
|
+
|
|
320
|
+
## The operator CLI: `bantamkit-memory`
|
|
321
|
+
|
|
322
|
+
The package installs **two** commands: `bantamkit-mcp`, the server, whose stdout is the JSON-RPC
|
|
323
|
+
wire, and `bantamkit-memory`, the operator CLI for memory-store lifecycle, which prints reports.
|
|
324
|
+
It is a second bin rather than a subcommand because report output on the server's stdout would
|
|
325
|
+
corrupt the transport, and `bantamkit-mcp`'s help is byte-compared with
|
|
326
|
+
`python -m bantamkit.mcpserver -h`.
|
|
354
327
|
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
added 95 packages in 5s
|
|
358
|
-
$ ls -l node_modules/.bin/
|
|
359
|
-
bantamkit-mcp -> ../bantamkit-mcp/dist/cli.js
|
|
360
|
-
bantamkit-memory -> ../bantamkit-mcp/dist/memory/cli.js
|
|
328
|
+
```bash
|
|
329
|
+
npx -y -p bantamkit-mcp bantamkit-memory status # without installing; -p is required
|
|
361
330
|
```
|
|
362
331
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
the transport, and `bantamkit-mcp`'s help is a byte-compared artifact against
|
|
368
|
-
`python -m bantamkit.mcpserver -h`, which a subparsers action would move.
|
|
369
|
-
|
|
370
|
-
**Amendment, 2026-09-11 (J46-26/J46-27).** "Not a thing you run by hand" is now half
|
|
371
|
-
true and the half that changed is worth knowing. Typing `bantamkit-mcp` at a prompt
|
|
372
|
-
with nothing after it no longer opens a mute server and blocks — it prints the help,
|
|
373
|
-
on stdout, exit 0, the same bytes `-h` prints. The discrimination is whether **stdin is
|
|
374
|
-
a terminal** and nothing else, so every host launch is unchanged: `"args": []` down a
|
|
375
|
-
pipe still starts the server and still answers `initialize`. The paragraph above stays
|
|
376
|
-
true of what it was describing — stdout is the wire, and nothing but frames goes down
|
|
377
|
-
it when a host is on the other end. What is new is that typing the command to see what
|
|
378
|
-
it does is now a reasonable thing to do. An argument after the command is an operator
|
|
379
|
-
asking for a configured server and still gets one: `bantamkit-mcp --store /tmp/x` at a
|
|
380
|
-
terminal serves. Compared between the two runtimes by
|
|
381
|
-
`tools/conformance/suites/cli.mjs` (`bare-at-a-tty`, `flagged-at-a-tty`,
|
|
382
|
-
`bare-over-a-pipe`).
|
|
383
|
-
|
|
384
|
-
Five subcommands, scoped to the writable **project** layer only — read-only grants and the
|
|
385
|
-
profile store are out of its reach by the code path, not by convention:
|
|
386
|
-
|
|
387
|
-
| subcommand | what it does |
|
|
332
|
+
The package name and the bin name differ, so plain `npx bantamkit-memory` would look for a
|
|
333
|
+
package called `bantamkit-memory`.
|
|
334
|
+
|
|
335
|
+
| Subcommand | What it does |
|
|
388
336
|
|---|---|
|
|
389
337
|
| `status` | index size, budget, headroom, archive count |
|
|
390
338
|
| `lint` | exit 1 if the store is malformed or over budget |
|
|
391
339
|
| `compact` | archive the stalest facts until the index fits |
|
|
392
340
|
| `archived` | list what compaction has moved out |
|
|
341
|
+
| `archive NAME` | move one named fact out |
|
|
393
342
|
| `restore NAME` | move an archived fact back |
|
|
394
343
|
|
|
395
|
-
Each takes `--store
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
```console
|
|
403
|
-
$ bantamkit-memory status --store store
|
|
404
|
-
store: store
|
|
405
|
-
facts: 5
|
|
406
|
-
index: 576 bytes
|
|
407
|
-
budget: 24000
|
|
408
|
-
headroom: 23424
|
|
409
|
-
archived: 0
|
|
410
|
-
$ bantamkit-memory lint --store store --budget 400
|
|
411
|
-
lint: FAIL — index is 576 bytes, budget is 400
|
|
412
|
-
try: bantamkit-memory compact --store store --budget 400
|
|
413
|
-
$ echo $?
|
|
414
|
-
1
|
|
415
|
-
$ bantamkit-memory compact --store store --budget 400
|
|
416
|
-
compacted 3 fact(s)
|
|
417
|
-
index: 576 -> 236 bytes (budget 400, target 267, reserve 133, headroom 164)
|
|
418
|
-
archived -> store/archive
|
|
419
|
-
assets-pack-has-eighty-four-files (project, 133 bytes)
|
|
420
|
-
ci-runner-is-macos-only (project, 97 bytes)
|
|
421
|
-
conformance-runner-entrypoint (reference, 110 bytes)
|
|
422
|
-
restore one with: bantamkit-memory restore <name> --store store
|
|
423
|
-
$ bantamkit-memory archived --store store
|
|
424
|
-
archived facts: 3 (store/archive)
|
|
425
|
-
assets-pack-has-eighty-four-files
|
|
426
|
-
ci-runner-is-macos-only
|
|
427
|
-
conformance-runner-entrypoint
|
|
428
|
-
$ bantamkit-memory restore ci-runner-is-macos-only --store store
|
|
429
|
-
restored 'ci-runner-is-macos-only' — index now 333/24000 bytes
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
`compact` printing every name that left is the point: `archive/` is a directory nothing
|
|
433
|
-
reads back on its own, so a compaction whose output is not shown is a silent deletion as
|
|
434
|
-
far as the operator is concerned.
|
|
435
|
-
|
|
436
|
-
Without installing, `npx -p bantamkit-mcp bantamkit-memory status` runs it out of the
|
|
437
|
-
registry. `-p` is not optional — the package name and this bin's name differ, and plain
|
|
438
|
-
`npx bantamkit-memory` would go looking for a package called `bantamkit-memory`. Measured
|
|
439
|
-
here against the local tarball rather than the registry, since this version is not
|
|
440
|
-
published:
|
|
441
|
-
|
|
442
|
-
```console
|
|
443
|
-
$ npx -y -p ./bantamkit-mcp-0.25.0.tgz bantamkit-memory status --store npxstore
|
|
444
|
-
store: npxstore
|
|
445
|
-
facts: 0
|
|
446
|
-
index: 0 bytes
|
|
447
|
-
budget: 24000
|
|
448
|
-
headroom: 24000
|
|
449
|
-
archived: 0
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
**The Python install does not provide this command**, which is why the two spellings
|
|
453
|
-
exist. Measured against the distribution in this repository's venv:
|
|
344
|
+
Each takes `--store STORE` or `--start START`; with neither, it resolves the project store the way
|
|
345
|
+
`Memory.layered()` does. It reaches the writable **project** layer only — read-only grants and the
|
|
346
|
+
profile store are out of reach by the code path, not by convention. Exit codes: `0` success, `1`
|
|
347
|
+
a failure to act on (over budget, a malformed fact, a refused restore), `2` a usage error, so
|
|
348
|
+
`lint` drops into a pre-commit hook or CI job unchanged. `compact` prints every name it moved,
|
|
349
|
+
because `archive/` is a directory nothing reads back on its own.
|
|
454
350
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
[
|
|
458
|
-
$ env PATH="$PWD/.venv/bin:/usr/bin:/bin" sh -c 'command -v bantamkit-memory'
|
|
459
|
-
$ echo $?
|
|
460
|
-
1
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
One console script, and it is the server. The Python operator therefore types
|
|
464
|
-
`python -m bantamkit.memory`, and the two CLIs are identical bytes after substituting one
|
|
465
|
-
for the other — except the wrap, because argparse's hanging indent is
|
|
466
|
-
`len(prefix) + len(prog) + 1`. The reason there is no third spelling both installs could
|
|
467
|
-
use lives in one place, the `prog` row of `docs/porting.md`'s divergence table, and this
|
|
468
|
-
page does not restate it. `docs/memory.md`'s *The operator CLI* is the full reference;
|
|
469
|
-
`tools/conformance/suites/memorycli.mjs` is the gate that compares the two.
|
|
351
|
+
The Python install has no such console script: there the same CLI is
|
|
352
|
+
`python -m bantamkit.memory`, identical bytes apart from the program name and its wrap. Full
|
|
353
|
+
reference: [docs/memory.md → The operator CLI](https://github.com/Ink01101011/bantamkit/blob/main/docs/memory.md#the-operator-cli).
|
|
470
354
|
|
|
471
|
-
##
|
|
355
|
+
## Memory stores are layered by default
|
|
472
356
|
|
|
473
|
-
With **no arguments
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
357
|
+
With **no arguments** — what every config above passes, and what production runs — the server
|
|
358
|
+
binds `Memory.layered`: the project store discovered from the working directory, plus the profile
|
|
359
|
+
layer, plus any `extra_stores` from `.bantamkit/config.yaml`. Recall lines are prefixed with their
|
|
360
|
+
layer: `[project] `, `[extra:<name>]`, `[profile]`.
|
|
477
361
|
|
|
478
|
-
`--store <path>` binds one store and drops the tag. It is a debugging flag
|
|
479
|
-
produced under `--store` is not
|
|
480
|
-
|
|
362
|
+
`--store <path>` binds one store and drops the tag. It is a debugging flag: a recall string
|
|
363
|
+
produced under `--store` is not one the deployment ever emits, and the cold-start gate asserts the
|
|
364
|
+
layered form for that reason.
|
|
481
365
|
|
|
482
366
|
## The asset pack
|
|
483
367
|
|
|
484
|
-
The pack is language-agnostic data
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
that directory is generated and git-ignored.
|
|
368
|
+
The pack is language-agnostic data — tool manifests, schemas, skills, rubrics, contract wording,
|
|
369
|
+
eval fixtures — that lives at the **repository root** and is shared verbatim with `runtime-py`.
|
|
370
|
+
npm cannot reach outside a package directory, so `scripts/sync-assets.mjs` vendors it into
|
|
371
|
+
`runtime-ts/assets/` on `prepack`; that directory is generated and git-ignored.
|
|
489
372
|
|
|
490
|
-
`build_identity` hashes **every byte of the whole tree**, not just the 20 files the tools
|
|
491
|
-
|
|
492
|
-
`
|
|
493
|
-
actually put in the tarball, never against the source tree.
|
|
373
|
+
`build_identity` hashes **every byte of the whole tree**, not just the 20 files the tools read, so
|
|
374
|
+
the pack ships whole — 91 files / 238,751 bytes on 2026-09-15 — or `assets_digest` and `build_id` change.
|
|
375
|
+
`test/packaging.test.mjs` asserts that against what `npm pack` would put in the tarball.
|
|
494
376
|
|
|
495
377
|
`assetsRoot()` mirrors `runtime-py/src/bantamkit/assets.py` arm for arm:
|
|
496
378
|
|
|
@@ -501,23 +383,19 @@ actually put in the tarball, never against the source tree.
|
|
|
501
383
|
|
|
502
384
|
## Sharing a store with the Python server
|
|
503
385
|
|
|
504
|
-
Both servers read and write the same memory store
|
|
505
|
-
not a nice-to-have. Two things to know:
|
|
386
|
+
Both servers read and write the same memory store; byte-compatibility is the product.
|
|
506
387
|
|
|
507
388
|
- **Concurrent writes are safe for the memory store and lossy for the checkpoint, in both
|
|
508
|
-
runtimes.** `index.md` is derived from
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
Python reference — reference behaviour reproduced, not something the port introduced. The
|
|
515
|
-
cursor check serialises the normal case; only the same-unit collision loses.
|
|
389
|
+
runtimes.** `index.md` is derived from `facts/`, so the last writer re-enumerates everything
|
|
390
|
+
and the index self-heals: 8 trials of two processes × 15 saves, zero disagreements. A
|
|
391
|
+
checkpoint is not: `shiftwork_clock_out` is read-modify-write, so two concurrent clock-outs on
|
|
392
|
+
the *same cursor unit* both answer `ok` and one history entry is lost — 10/10 trials on Node
|
|
393
|
+
**and** 10/10 on the Python reference. The cursor check serialises the normal case; only the
|
|
394
|
+
same-unit collision loses.
|
|
516
395
|
- **Do not hand-edit a fact file's `name`, `description` or `type` to a bare non-string.**
|
|
517
|
-
`description: 2026` is a YAML integer
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
reaches you through an editor. See `src/memory/factfile.ts:257`.
|
|
396
|
+
`description: 2026` is a YAML integer. Python interpolates it and carries on; this port refuses
|
|
397
|
+
the whole store with `malformed fact file …`. Quote it: `description: '2026'`. Every fact the
|
|
398
|
+
tools *write* is quoted correctly (`src/memory/factfile.ts:257`).
|
|
521
399
|
|
|
522
400
|
## Development
|
|
523
401
|
|
|
@@ -531,13 +409,23 @@ npm pack --dry-run # vendors the pack via prepack, lists the tarball
|
|
|
531
409
|
From the repository root:
|
|
532
410
|
|
|
533
411
|
```sh
|
|
534
|
-
node tools/conformance/run.mjs --all # Node vs Python,
|
|
412
|
+
node tools/conformance/run.mjs --all # Node vs Python, 8,130 cases on 2026-09-15
|
|
535
413
|
node tools/conformance/npx-cold-start.mjs # pack, cold npx, warm npx, PATH
|
|
536
|
-
node tools/conformance/npx-cold-start.mjs --offline # + the no-
|
|
414
|
+
node tools/conformance/npx-cold-start.mjs --offline # + the no-network arms (299.94 s on 2026-09-15)
|
|
537
415
|
```
|
|
538
416
|
|
|
539
|
-
The conformance harness shells out to a CPython
|
|
417
|
+
The conformance harness shells out to a CPython for the reference side. That is a
|
|
540
418
|
**development-time** dependency of the test tooling; nothing under `tools/` ships, and
|
|
541
|
-
`files: ["dist", "assets"]` is the whole published surface.
|
|
542
|
-
|
|
543
|
-
|
|
419
|
+
`files: ["dist", "assets"]` is the whole published surface. Runtime dependencies: exactly one,
|
|
420
|
+
`@modelcontextprotocol/sdk`, pinned to `1.30.0`.
|
|
421
|
+
|
|
422
|
+
## Measurements and history
|
|
423
|
+
|
|
424
|
+
Every number on this page was measured on the machine that wrote it, with a command you can
|
|
425
|
+
rerun. The measurements, dated amendments and transcripts that used to fill this page are in
|
|
426
|
+
[docs/install.md → npm package: measured detail](https://github.com/Ink01101011/bantamkit/blob/main/docs/install.md#npm-package-measured-detail):
|
|
427
|
+
cold-start cost and package size, the registry-unreachable and offline tables, what `--install`
|
|
428
|
+
recorded before and after 0.34.0, `--update` transcripts, the login-less PATH probe, what `npx`
|
|
429
|
+
gives up versus the `tools/bantamkit-mcp` launcher, and the `bantamkit-memory` session
|
|
430
|
+
transcripts. Where the two runtimes deliberately differ:
|
|
431
|
+
[docs/porting.md](https://github.com/Ink01101011/bantamkit/blob/main/docs/porting.md#where-the-two-runtimes-deliberately-differ).
|