@cntxt-labs/medha-cli 0.5.0
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/LICENSE +21 -0
- package/README.md +213 -0
- package/bin/medha.cjs +67 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nimishph
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# medha
|
|
2
|
+
|
|
3
|
+
**Evidential memory for the rules, recipes and tools your agents rely on.**
|
|
4
|
+
|
|
5
|
+
Agents accumulate rules ("never leave `console.log` in a commit"), recipes ("how we run migrations")
|
|
6
|
+
and tools (an MCP server, a linter). Some of them help. Some are stale, wrong, or quietly ignored.
|
|
7
|
+
Most memory systems store *what was said* and treat all of it as equally true.
|
|
8
|
+
|
|
9
|
+
Medha stores *what happened*: each time something was applied, rejected, skipped, or checked by a
|
|
10
|
+
guard. From that record it computes a **trust hint** for every entity. It reports evidence and never
|
|
11
|
+
decides an action; you and your agent decide what to do with it.
|
|
12
|
+
|
|
13
|
+
- **Earned, not asserted.** A new rule starts on probation. Usage alone never makes it trusted; a
|
|
14
|
+
passing guard is required.
|
|
15
|
+
- **Honest about small samples.** Trust uses a Wilson lower bound, so 2 successes out of 2 is not
|
|
16
|
+
treated like 200 out of 200.
|
|
17
|
+
- **Explainable.** Every number can be traced: `medha show` splits trust into its components and
|
|
18
|
+
`medha explain-threshold` says which bars were cleared and which were not.
|
|
19
|
+
- **Safe to try.** `medha simulate` shows what a signal would do without recording anything.
|
|
20
|
+
- **One binary, no server.** CLI and MCP server in a single executable. State is an append-only
|
|
21
|
+
episode log you can back up, compact, sync, or replay.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm install -g @cntxt-labs/medha-cli # or: bun add -g, pnpm add -g, npx @cntxt-labs/medha-cli
|
|
27
|
+
medha --version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It is a single self-contained program: no Node, Bun or Python is needed to run it. Linux, macOS (Apple silicon and Intel) and Windows are supported.
|
|
31
|
+
|
|
32
|
+
Prefer no package manager? Download the archive for your platform from the GitHub release, unpack it
|
|
33
|
+
and put `medha` (or `medha.exe`) on your `PATH`.
|
|
34
|
+
|
|
35
|
+
## A first session
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
medha init # creates .medha/ in the current directory
|
|
39
|
+
medha propose --id no-console-log --source review # a candidate rule enters on probation
|
|
40
|
+
```
|
|
41
|
+
```
|
|
42
|
+
medha: proposed rule/no-console-log (not promoted)
|
|
43
|
+
reason: Requires >= 2 converging sources; saw 1 (review)
|
|
44
|
+
trust: 0.000 status: probation
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Promotion needs agreement from at least two independent sources. Now record what happens as the
|
|
48
|
+
rule is used:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
medha record --id no-console-log --signal APPLY --ensure # used, and it worked
|
|
52
|
+
medha record --id no-console-log --signal APPLY
|
|
53
|
+
medha guard --id no-console-log --ok --guard review # a check that the rule still holds
|
|
54
|
+
```
|
|
55
|
+
```
|
|
56
|
+
medha: recorded APPLY on rule/no-console-log trust: 0.103 status: probation
|
|
57
|
+
medha: recorded APPLY on rule/no-console-log trust: 0.171 status: probation
|
|
58
|
+
medha: guard passed on rule/no-console-log trust: 0.378 status: active
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
See why it is where it is:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
medha show --id no-console-log
|
|
65
|
+
```
|
|
66
|
+
```
|
|
67
|
+
medha: rule/no-console-log (known)
|
|
68
|
+
status: active
|
|
69
|
+
trust: 0.378 (wilson 0.342, guard 1.000, recency 1.000, durability 1.104, ceiling 1.000)
|
|
70
|
+
evidence: 2/2 successes, wilson lower bound 0.342
|
|
71
|
+
temporal: ema 0.595, drift no (delta 0.095)
|
|
72
|
+
clears: trusted no, active yes
|
|
73
|
+
```
|
|
74
|
+
```sh
|
|
75
|
+
medha explain-threshold --id no-console-log
|
|
76
|
+
```
|
|
77
|
+
```
|
|
78
|
+
trusted: not met
|
|
79
|
+
no trust 0.378 >= 0.6
|
|
80
|
+
no uses 2 >= 5
|
|
81
|
+
active: MET
|
|
82
|
+
ok trust 0.378 >= 0.25
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Before recording something consequential, preview it:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
medha simulate --id no-console-log --signal REJECT_RULE
|
|
89
|
+
```
|
|
90
|
+
```
|
|
91
|
+
medha: simulate REJECT_RULE on rule/no-console-log
|
|
92
|
+
trust: 0.378 -> 0.229 (delta -0.149)
|
|
93
|
+
status: active -> probation (changed)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Every command accepts `--json`. `medha --help` and `medha <command> --help` list all options.
|
|
97
|
+
|
|
98
|
+
## Concepts
|
|
99
|
+
|
|
100
|
+
**Entity.** The thing being trusted, addressed by `namespace` (default empty), `kind` and `id`. The
|
|
101
|
+
built-in kinds are `rule`, `recipe` and `tool`; you can register your own.
|
|
102
|
+
|
|
103
|
+
**Signal.** One piece of evidence about an entity.
|
|
104
|
+
|
|
105
|
+
| Signal | Meaning |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `APPLY` | It was used and it worked. |
|
|
108
|
+
| `REJECT_RULE` | A human rejected it. |
|
|
109
|
+
| `SKIP` | It did not apply. Neutral: it never counts for or against. |
|
|
110
|
+
|
|
111
|
+
**Guard.** An independent check that the entity is still correct (a test, a linter run, a review).
|
|
112
|
+
Report the result with `medha guard --ok` or `--fail`.
|
|
113
|
+
|
|
114
|
+
**Episode.** Every proposal, signal and guard result is an immutable entry in an append-only log.
|
|
115
|
+
Entity state is a fold over that log, so it can always be rebuilt, audited, or corrected
|
|
116
|
+
(`medha retract`, `medha remove-episode`).
|
|
117
|
+
|
|
118
|
+
### How trust is computed
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
trust = min( ceiling, wilson × recency × durability × guard )
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
| Component | What it does |
|
|
125
|
+
|---|---|
|
|
126
|
+
| **Wilson lower bound** | A conservative estimate of the true success rate given `k` successes in `n` trials. Small samples score low. |
|
|
127
|
+
| **Recency** | Evidence decays with a 45-day half-life, down to a floor, so old wins fade. |
|
|
128
|
+
| **Durability** | A bonus (up to 1.5×) for evidence that has held up over time. |
|
|
129
|
+
| **Guard** | Scales trust by the outcome of guard results. |
|
|
130
|
+
| **Ceiling** | Caps trust at **0.5 while no guard has passed**, so usage alone can never reach `trusted`. |
|
|
131
|
+
|
|
132
|
+
Separately, an exponential moving average watches for **drift**: entities whose recent behaviour
|
|
133
|
+
diverges from their baseline show up in `medha drift`.
|
|
134
|
+
|
|
135
|
+
`medha params` prints every constant and threshold.
|
|
136
|
+
|
|
137
|
+
### Lifecycle
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
probation ──► active ──► trusted
|
|
141
|
+
│ │
|
|
142
|
+
└────────────┴──► quarantined / retired (repeated rejection; trust below 0.1)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
| Status | Bar |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `active` | trust ≥ 0.25 |
|
|
148
|
+
| `trusted` | trust ≥ 0.6, at least 5 uses, and a passing guard |
|
|
149
|
+
|
|
150
|
+
## Use it from an agent (MCP)
|
|
151
|
+
|
|
152
|
+
Register the server in your project's `.mcp.json`:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{ "mcpServers": { "medha": { "command": "medha", "args": ["mcp", "serve"] } } }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Then copy [`SKILL.md`](SKILL.md) to
|
|
159
|
+
`.claude/skills/medha/SKILL.md` so the agent knows when and how to use it.
|
|
160
|
+
|
|
161
|
+
| Tool | Purpose |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `hints` | Batch-fetch trust hints for the entities you are about to rely on. Returns `{ hints, unknown }`; treat `unknown` as probation. |
|
|
164
|
+
| `list_entities` | Paginated search by kind, status, namespace or drift. |
|
|
165
|
+
| `show_entity` | Full detail for one entity: components, temporal state, recent episodes. |
|
|
166
|
+
| `record_signal` | Record `APPLY`, `REJECT_RULE`, `SKIP`, and so on. Returns `recorded: false` for an unknown entity unless `ensure` is set. |
|
|
167
|
+
| `report_guard` | Record a guard result. |
|
|
168
|
+
| `propose` | Submit a candidate entity. |
|
|
169
|
+
| `drift` | List drifting entities. |
|
|
170
|
+
| `simulate` | Preview a signal's effect; persists nothing. |
|
|
171
|
+
| `status` | Engine health and preflight. |
|
|
172
|
+
|
|
173
|
+
### Fitting trust into a prompt
|
|
174
|
+
|
|
175
|
+
`medha pack --budget 2000` selects the active and probation rules that fit a token budget, so a
|
|
176
|
+
host can inject the most trusted guidance without overrunning its context.
|
|
177
|
+
|
|
178
|
+
## Inspect and share
|
|
179
|
+
|
|
180
|
+
- **`medha ui`** launches a local web dashboard over the store.
|
|
181
|
+
- **`medha report`** writes a standalone, offline HTML snapshot you can attach to a review.
|
|
182
|
+
- **`medha sync status|pull|push`** shares evidence between machines through a git ref or a file.
|
|
183
|
+
Registries travel with the episodes, so custom kinds and signals do not have to be copied by hand.
|
|
184
|
+
|
|
185
|
+
## Extend it
|
|
186
|
+
|
|
187
|
+
- **Kinds and signals.** Register your own in `.medha/config.json`. A kind can set its own trust
|
|
188
|
+
thresholds and recency half-life, and can weight evidence by a signal's value (for example, a
|
|
189
|
+
timeout counts less against a tool than a crash).
|
|
190
|
+
- **Weight updaters.** Swap how evidence moves trust with `medha updater list` and `medha updater fork <name>`, which scaffolds a custom one.
|
|
191
|
+
|
|
192
|
+
## Maintain it
|
|
193
|
+
|
|
194
|
+
```sh
|
|
195
|
+
medha maintain preflight # verify store integrity and registry match
|
|
196
|
+
medha maintain compact --older-than 90 # fold old episodes into baselines, and say what was folded
|
|
197
|
+
medha maintain backup snapshot.json # atomic, portable snapshot
|
|
198
|
+
medha maintain restore snapshot.json
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Everything lives under `.medha/`. `medha init` scaffolds a `.medha/.gitignore` and a
|
|
202
|
+
`.medha/README.md` for you: `config.json` (the registries) is meant to be committed, while the
|
|
203
|
+
store data itself is gitignored by default — share it with `medha sync` instead, since it has its
|
|
204
|
+
own conflict-resolving merge, not git's. Delete or edit `.medha/.gitignore` if you'd rather commit
|
|
205
|
+
the store file directly as a simpler, manual sync.
|
|
206
|
+
|
|
207
|
+
## Author & Attribution
|
|
208
|
+
|
|
209
|
+
Authored by **[@nimishph](https://github.com/nimishph)**.
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT © [Nimish Phalnikar](https://github.com/nimishph)
|
package/bin/medha.cjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
// The command a package manager links onto the PATH. The program itself is a compiled binary in
|
|
4
|
+
// a per-platform package (`@cntxt-labs/medha-<os>-<cpu>`), installed alongside this one because
|
|
5
|
+
// this package lists them all as optional dependencies and a package manager keeps only the one
|
|
6
|
+
// that matches the machine. This file finds it and runs it.
|
|
7
|
+
|
|
8
|
+
const { spawnSync } = require('node:child_process');
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
|
|
11
|
+
const SUPPORTED = ['linux-x64', 'linux-arm64', 'darwin-arm64', 'darwin-x64', 'win32-x64'];
|
|
12
|
+
|
|
13
|
+
/** The package that holds the program for a platform, or `undefined` when there is none. */
|
|
14
|
+
function platformPackage(platform, cpu) {
|
|
15
|
+
const key = `${platform}-${cpu}`;
|
|
16
|
+
return SUPPORTED.includes(key) ? `@cntxt-labs/medha-${key}` : undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Where the installed program is, or why it cannot be found. */
|
|
20
|
+
function locate(platform, cpu, resolve) {
|
|
21
|
+
const name = platformPackage(platform, cpu);
|
|
22
|
+
if (name === undefined) {
|
|
23
|
+
return {
|
|
24
|
+
problem: `medha has no build for ${platform} on ${cpu}. It runs on: ${SUPPORTED.join(', ')}.`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const file = platform === 'win32' ? 'medha.exe' : 'medha';
|
|
28
|
+
try {
|
|
29
|
+
return { program: resolve(`${name}/bin/${file}`) };
|
|
30
|
+
} catch (failure) {
|
|
31
|
+
return {
|
|
32
|
+
problem:
|
|
33
|
+
`The ${name} package is not installed (${failure.code ?? failure.message}). ` +
|
|
34
|
+
'It is an optional dependency of @cntxt-labs/medha-cli: reinstall without --no-optional, or ' +
|
|
35
|
+
`install ${name} directly.`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function main() {
|
|
41
|
+
const found = locate(process.platform, process.arch, require.resolve);
|
|
42
|
+
if (found.problem !== undefined) {
|
|
43
|
+
process.stderr.write(`medha: ${found.problem}\n`);
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const child = spawnSync(found.program, process.argv.slice(2), {
|
|
48
|
+
stdio: 'inherit',
|
|
49
|
+
cwd: process.cwd(),
|
|
50
|
+
});
|
|
51
|
+
if (child.error) {
|
|
52
|
+
process.stderr.write(
|
|
53
|
+
`medha: could not start ${path.basename(found.program)}: ${child.error.message}\n`,
|
|
54
|
+
);
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (child.signal) {
|
|
59
|
+
process.kill(process.pid, child.signal);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
process.exitCode = child.status ?? 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = { SUPPORTED, platformPackage, locate };
|
|
66
|
+
|
|
67
|
+
if (require.main === module) main();
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cntxt-labs/medha-cli",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Evidential memory for rules, recipes and tools: records what happened and returns trust hints. CLI and MCP server.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"agent-memory",
|
|
8
|
+
"trust",
|
|
9
|
+
"evidence",
|
|
10
|
+
"ai-agents",
|
|
11
|
+
"cli"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "nimishph",
|
|
16
|
+
"url": "https://github.com/nimishph"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/nimishph/medha#readme",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/nimishph/medha.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/nimishph/medha/issues"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"medha": "bin/medha.cjs"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"bin",
|
|
32
|
+
"SKILL.md",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"optionalDependencies": {
|
|
43
|
+
"@cntxt-labs/medha-linux-x64": "0.5.0",
|
|
44
|
+
"@cntxt-labs/medha-linux-arm64": "0.5.0",
|
|
45
|
+
"@cntxt-labs/medha-darwin-arm64": "0.5.0",
|
|
46
|
+
"@cntxt-labs/medha-darwin-x64": "0.5.0",
|
|
47
|
+
"@cntxt-labs/medha-win32-x64": "0.5.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
51
|
+
"@cntxt-labs/medha": "workspace:*",
|
|
52
|
+
"@cntxt-labs/medha-core": "workspace:*",
|
|
53
|
+
"@cntxt-labs/medha-store": "workspace:*",
|
|
54
|
+
"citty": "^0.2.2",
|
|
55
|
+
"zod": "^4.6.5"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "bun run ../tooling/package-release.ts"
|
|
59
|
+
}
|
|
60
|
+
}
|