Repository navigation
Extensions
Extensions are optional modules that add task-specific behaviour on top of the core: commands, procedures, checklists, reference catalogues and, where you allow it, small programs. The core stays a plain specification. Everything that needs more lives in an extension you choose to install.
| Extension | Version | What it is for | Reaches outside the repository | Ships code |
|---|---|---|---|---|
| mem-commands | 1.0.0 | Review plans before building them, verify "done" claims, define your own commands | no | no |
| mem-toolbox | 1.0.3 | Which tool or library to use for a task, and whether it is installed on this machine | its machine file in ~/.mem/, and approved package installs into a dedicated environment |
no |
| mem-workspace | 1.0.0 | Knowledge base in a private repository beside a public one, plus an optional wiki | no | no |
| mem-stats | 0.1.1 | Measure what agent sessions consume, into a local ledger of counts | no | yes |
| mem-optimize | 0.1.2 | Guided restarts, long-pause guard, re-orientation after compaction, KB page weight | no | yes |
mem-cleaner is also in the repository, but it is still in development and not yet in the catalogue.
Each extension lives in its own folder under KB_ROOT/extensions/, and extensions/EXT.md is the routing table
that registers them:
extensions/
EXT.md which extensions are registered, with status and version
<extension-id>/
index.md what it does, its commands, its options (the "base" layer)
... other base files: procedures, catalogues, code
custom/ your project's additions (the "custom" layer)
index.md
It has two layers:
- The base layer is maintained upstream and replaced when the extension is updated, so local edits to it are lost.
- The custom layer, under
custom/, is yours. It is never shipped and never touched by an update. Project entries, your own commands and local overrides go there.
An extension you have not customised simply has no custom/ folder, which is normal. A few extensions declare a
bootstrap entry, a single file under custom/ created at installation because it holds data that would
otherwise have nowhere obvious to go. mem-workspace uses one for the record of which folder holds which
repository.
Each extension states whether its base or your custom layer wins when both define the same entry, because the right answer differs. Letting a custom entry shadow a command could hijack it. Letting your local knowledge override a reference entry is usually right.
MEM publishes a catalogue, the manifest: which extensions exist, what each provides, and the exact list of files that make each one up.
The catalogue is not a permission slip. It is fetched over the network and its URL can be changed in configuration, so it never decides what runs in your repository. An extension is used only when both are true:
- its files are in your repository under
KB_ROOT/extensions/; - it is registered
activeinEXT.md.
Both are files you review in a pull request like anything else. That gives two clear moments:
| Moment | What MEM requires |
|---|---|
| Installing an extension, letting it write files, run commands or act outside the repository | Your explicit approval, before it happens. A notice afterwards would be worthless |
| Using an extension you already registered | Disclosure, not another prompt. The agent names the extension on its acknowledgement line |
An extension that is not in the catalogue is perfectly legitimate: writing your own is what the custom layer is for. It just gets no automatic install offer and no borrowed trust, and the agent says it is project-made the first time it uses it in a session.
There are three ways an extension gets offered:
- The catalogue offer, at first initialization and after any update that brings an extension you were never asked about. One multiple-choice question lists them all, noting that some may install additional software.
-
A command nothing provides yet. Type
MEM STATS REPORTwithout mem-stats installed and the agent offers to install the extension that provides it, once per session. - Asking. "Install mem-workspace" works.
In every case the agent first shows one confirmation naming every file it will write and the URL it comes from,
with code files named as code, and writes nothing before you approve. An extension you decline is recorded as
declined in EXT.md and not offered again until you ask for it.
An install never deletes an extension's folder first, which is how your custom/ survives.
Updating MEM.md updates the core only, so an installation could quietly run a current core against extensions
published months ago. With extensions_check_updates: true (the default), every MEM update also compares each
installed extension's version with the catalogue's:
> Extension update available: `mem-toolbox` 1.0.0 -> 1.0.1 (manifest). Not applied; approval required.The check reports and proposes, never installs. A version gap is not permission. Approving an update writes
exactly the files the catalogue lists for that extension, so custom/ and EXT.md are safe by construction.
Extensions you wrote yourself are reported as unchecked, because there is nothing to compare them against.
MEM STATUS shows both versions at any time.
To refuse an update permanently, change the extension's status in EXT.md.
Almost everything MEM distributes is Markdown an agent reads. A few extensions need a program: a hook that runs at
the end of every agent turn, a transactional file replacement that must finish even if the conversation does not.
They declare executable content: yes, and MEM treats them differently:
-
Off by default. They are only installed and run when
extensions_allow_executable_content: true. While it is false, the catalogue offer still lists them, marked as needing the setting, and choosing one leads to a question about enabling it. The agent never changes the setting on its own. - Approved as code. Installing asks for approval that names the executable files as executable, separately from the rest. Approving documentation and approving code are different decisions.
- Approved again on update, because an update replaces code already in your repository.
- Small enough to read. The code is committed to your repository, so each update arrives as a diff you can review in a pull request. That only means something if the code stays small, which is a constraint MEM places on itself.
-
Data, not plugins. Such code never loads or runs code from your project; definitions under
custom/are declarative data. - No windows. It must run without opening console windows on your desktop, since hooks fire on every turn.
MEM does not pretend to sandbox this code. "An extension cannot grant itself permissions" is a rule an agent can honour and a program cannot, so for code the safeguard is the approval and your review, not a promise.
The core itself still needs no runtime and no dependencies; extensions are optional, which is what keeps that true.
An extension that sends HTTP requests or notifications, deploys, opens tickets or writes to an external system needs
your explicit confirmation each time, unless extensions_allow_external_side_effects: true waives it. Some
extensions ask regardless: mem-toolbox always asks before installing a package, because that runs
third-party code. No extension may ever send secrets, tokens, real environment variable values, raw logs or
unnecessary personal data.
Copy extensions/EXT.index.template.md, give the extension a folder with an index.md, and register it in
EXT.md with its id, path, status, version, triggers, a one-line description, whether it acts outside the repository
or ships code, and its default mode. Its options are named extensions_<id>_<option>. A command of your own that
does not need a whole extension can be written with MEM DEFINE from mem-commands.
To turn all extensions off at once, set extensions_enabled: false: only the core commands remain, and nothing is
offered or checked.
Extensions
- mem-commands
- mem-toolbox
- mem-workspace
- mem-stats
- mem-optimize
- mem-cleaner (in development)