mnemos-capture 1.2.1 → 1.4.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/README.md +311 -232
- package/dist/cli/config.js +43 -15
- package/dist/cli/hooks.js +4 -4
- package/dist/cli/index.js +22 -20
- package/dist/cli/kos.js +8 -8
- package/dist/cli/mcp-server.js +61 -15
- package/dist/cli/version-check.js +1 -1
- package/package.json +24 -16
package/README.md
CHANGED
|
@@ -1,360 +1,439 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<br>
|
|
3
|
+
<a href="https://mnemos-capture.vercel.app">
|
|
4
|
+
<picture>
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="public/mnemos-hero-dark.gif">
|
|
6
|
+
<img src="public/mnemos-hero-light.gif" width="160" height="160" alt="xkg">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
<br>
|
|
10
|
+
<br>
|
|
11
|
+
<p>
|
|
12
|
+
<a href="https://www.npmjs.com/package/mnemos-capture"><img src="https://img.shields.io/npm/v/mnemos-capture?color=1c74d8&labelColor=000820&style=flat" alt="npm" /></a>
|
|
13
|
+
<img src="https://img.shields.io/badge/MCP-compatible-9dd8f5?labelColor=000820&style=flat" alt="MCP" />
|
|
14
|
+
<img src="https://img.shields.io/badge/license-MIT-f0f4f8?labelColor=000820&style=flat" alt="MIT" />
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
## xkg
|
|
19
|
+
|
|
20
|
+
Humans are constantly exposed to useful knowledge, domain expertise, and external input. But there is no bridge between what humans know and what their AI workers know and do.
|
|
21
|
+
|
|
22
|
+
xkg is the knowledge graph for AI workers that bridges human knowledge into context they can use.
|
|
23
|
+
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
- [xkg](#xkg)
|
|
27
|
+
- [How it works](#how-it-works)
|
|
28
|
+
- [Start here](#start-here)
|
|
29
|
+
- [Connect your AI workers](#connect-your-ai-workers)
|
|
30
|
+
- [On the web](#on-the-web)
|
|
31
|
+
- [Claude](#claude)
|
|
32
|
+
- [ChatGPT](#chatgpt)
|
|
33
|
+
- [Grok](#grok)
|
|
34
|
+
- [In the terminal](#in-the-terminal)
|
|
35
|
+
- [Cursor](#cursor)
|
|
36
|
+
- [VS Code](#vs-code)
|
|
37
|
+
- [Codex](#codex)
|
|
38
|
+
- [Gemini CLI](#gemini-cli)
|
|
39
|
+
- [Claude Code](#claude-code)
|
|
40
|
+
- [Claude Desktop](#claude-desktop)
|
|
41
|
+
- [Anything MCP](#anything-mcp)
|
|
42
|
+
- [Workflow](#workflow)
|
|
43
|
+
- [What's inside](#whats-inside)
|
|
44
|
+
- [Your context stays in GitHub](#your-context-stays-in-github)
|
|
45
|
+
- [CLI](#cli)
|
|
46
|
+
- [Roadmap](#roadmap)
|
|
47
|
+
- [License](#license)
|
|
4
48
|
|
|
5
|
-
|
|
49
|
+
## How it works
|
|
6
50
|
|
|
7
|
-
|
|
8
|
-
<img src="https://img.shields.io/npm/v/mnemos-capture" alt="npm" />
|
|
9
|
-
<img src="https://img.shields.io/badge/license-MIT-blue" alt="License" />
|
|
10
|
-
<img src="https://img.shields.io/badge/MCP-compatible-green" alt="MCP" />
|
|
11
|
-
</p>
|
|
51
|
+
You find useful stuff, you capture through the web app, then xkg connects it into a knowledge graph, and makes it available to the AI workers you already use.
|
|
12
52
|
|
|
13
|
-
|
|
53
|
+
xkg will continuously compound that knowledge over time — keeping AI workers' context up to date as human knowledge evolves.
|
|
14
54
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<em>Mnemos converts one into the other.</em>
|
|
18
|
-
</p>
|
|
19
|
-
|
|
20
|
-
<p align="center">A knowledge pipeline that turns what you learn into actionable context for AI agents.</p>
|
|
55
|
+
> [!IMPORTANT]
|
|
56
|
+
> We are migrating from **mnemos** / **Xmu** to **xkg**. The app URL, this GitHub repo, and the npm package still say `mnemos-capture`. Sorry for the inconvenience.
|
|
21
57
|
|
|
22
|
-
|
|
58
|
+
## Start here
|
|
23
59
|
|
|
24
|
-
|
|
60
|
+
You do not need a terminal to start.
|
|
25
61
|
|
|
26
|
-
|
|
62
|
+
### 1. Create your account
|
|
27
63
|
|
|
28
|
-
|
|
64
|
+
Open **[mnemos-capture.vercel.app](https://mnemos-capture.vercel.app)** and sign in with GitHub.
|
|
29
65
|
|
|
30
|
-
|
|
66
|
+
xkg will:
|
|
31
67
|
|
|
32
|
-
|
|
68
|
+
1. Create a **private** GitHub repo for your knowledge (you can opt to make it public)
|
|
69
|
+
2. Ask for your LLM provider API key — Anthropic, OpenAI, or Google. Your key, your cost.
|
|
70
|
+
3. Let you set a PIN (6+ characters) for quick unlock on this device
|
|
71
|
+
4. Show your **xkg API key** once — save it if you want to connect an AI worker
|
|
33
72
|
|
|
34
|
-
|
|
73
|
+
That's the whole setup. No repo to clone. No database. No CLI required.
|
|
35
74
|
|
|
75
|
+
### 2. Capture something
|
|
36
76
|
|
|
37
|
-
|
|
77
|
+
In the app, paste a URL, a note, a doc excerpt, a transcript, or an idea, then hit **Capture**.
|
|
38
78
|
|
|
39
|
-
|
|
79
|
+
xkg extracts the **core idea**, **key takeaways**, **where to apply it**, and the **capture type**, then commits Markdown to your GitHub repo.
|
|
40
80
|
|
|
41
|
-
|
|
81
|
+
On a phone: open the app → **Share → Add to Home Screen**. It runs like a native app.
|
|
42
82
|
|
|
43
|
-
|
|
83
|
+
### 3. Connect a worker (optional)
|
|
44
84
|
|
|
45
|
-
|
|
46
|
-
- Ask for your API key (your provider, your key — Mnemos never pays for your API calls)
|
|
47
|
-
- Set a PIN so you can unlock the app quickly on mobile
|
|
85
|
+
Skip this if you only want the app today. When you're ready, pick your tool under [Connect your AI workers](#connect-your-ai-workers). Capture now, connect later — the knowledge is already in your repo.
|
|
48
86
|
|
|
49
|
-
|
|
87
|
+
## Connect your AI workers
|
|
50
88
|
|
|
51
|
-
|
|
89
|
+
xkg is LLM-agnostic. Any worker that speaks MCP can use the same knowledge.
|
|
52
90
|
|
|
53
|
-
|
|
91
|
+
Two primitives:
|
|
54
92
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
claude mcp add mnemos -- npx -y mnemos-capture@latest serve-mcp --key <your-mcp-key>
|
|
93
|
+
```text
|
|
94
|
+
https://mnemos-capture.vercel.app/api/mcp
|
|
58
95
|
```
|
|
59
96
|
|
|
60
|
-
**Any MCP-compatible client** (Cursor, Continue, Gemini CLI, etc.) — point it at the stdio proxy:
|
|
61
97
|
```bash
|
|
62
|
-
npx -y mnemos-capture@latest serve-mcp --key
|
|
98
|
+
npx -y mnemos-capture@latest serve-mcp --key YOUR_API_KEY
|
|
63
99
|
```
|
|
64
100
|
|
|
65
|
-
The
|
|
101
|
+
The CLI binary is **`xkg`** (also `xmu` and `mnemos-capture`). `npx` still uses the package name `mnemos-capture`. An MCP server already registered as `xmu` or `mnemos` keeps working.
|
|
66
102
|
|
|
67
|
-
|
|
103
|
+
**On the web** — paste the URL (no terminal). **In the terminal** — run the command. Finish xkg onboarding first, then ask: *list my inbox* or *brief me*.
|
|
68
104
|
|
|
69
|
-
|
|
105
|
+
### On the web
|
|
70
106
|
|
|
71
|
-
|
|
72
|
-
capture "The Mom Test — don't ask if your idea is good, ask about their life."
|
|
73
|
-
```
|
|
107
|
+
Name the connector `xkg`, paste `https://mnemos-capture.vercel.app/api/mcp`, sign in with GitHub when asked.
|
|
74
108
|
|
|
75
|
-
|
|
109
|
+
#### Claude
|
|
76
110
|
|
|
111
|
+
1. Settings → Connectors → Add custom connector
|
|
77
112
|
|
|
78
|
-
|
|
113
|
+
#### ChatGPT
|
|
79
114
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
C -->|session start| D["Briefing\nranked suggestions + plan"]
|
|
85
|
-
D -->|generate_plan| E["Implementation plan\nsaved to plans/"]
|
|
86
|
-
E -->|mnemos kos| F["Your AI assistant\nexecutes in isolated worktree"]
|
|
87
|
-
F -->|verify| G["Branch ready\nto review & merge"]
|
|
88
|
-
|
|
89
|
-
style A fill:#1a1a2e,stroke:#444,color:#fff
|
|
90
|
-
style B fill:#2A62C6,stroke:#1a4a9e,color:#fff
|
|
91
|
-
style C fill:#2d8a4e,stroke:#1e6b3a,color:#fff
|
|
92
|
-
style D fill:#d4a843,stroke:#b8912e,color:#fff
|
|
93
|
-
style E fill:#2A62C6,stroke:#1a4a9e,color:#fff
|
|
94
|
-
style F fill:#1a1a2e,stroke:#444,color:#fff
|
|
95
|
-
style G fill:#2d8a4e,stroke:#1e6b3a,color:#fff
|
|
96
|
-
```
|
|
115
|
+
1. Settings → Plugins → Browse plugins
|
|
116
|
+
2. Name it xkg
|
|
117
|
+
3. Paste `https://mnemos-capture.vercel.app/api/mcp`
|
|
118
|
+
4. Sign in with GitHub when asked
|
|
97
119
|
|
|
98
|
-
|
|
99
|
-
2. **Brief** — at session start, the `--briefing` flag sends your project context (branch, recent commits, CLAUDE.md) to Mnemos. It returns ranked suggestions — *why* each insight matters now, *what* applying it achieves, *where* in your codebase.
|
|
100
|
-
3. **Plan** — `generate_plan` reads your selected captures and produces a structured Markdown plan: Codebase Mapping table, per-file steps with effort tiers (`simple` / `complex` / `architectural`), and a Verification Checklist.
|
|
101
|
-
4. **Execute** — `mnemos kos` (coming) creates an isolated git worktree, launches your configured AI assistant with the plan as its contract, and runs the verification checklist when it's done.
|
|
120
|
+
#### Grok
|
|
102
121
|
|
|
122
|
+
1. Open [grok.com/connectors](https://grok.com/connectors) → New Connector → Custom
|
|
103
123
|
|
|
104
|
-
|
|
124
|
+
### In the terminal
|
|
105
125
|
|
|
106
|
-
|
|
126
|
+
The same command works in every CLI — Cursor, Codex, Gemini CLI, VS Code, Claude Code, or anything that can launch a local MCP server:
|
|
107
127
|
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
- **Optimization techniques** — prompt engineering, caching strategies, latency improvements
|
|
112
|
-
- **Your own ideas** — architecture decisions, workflow changes, things you want your agents to act on later
|
|
113
|
-
- **Transcripts and talks** — signal extracted, ready to apply
|
|
128
|
+
```bash
|
|
129
|
+
npx -y mnemos-capture@latest serve-mcp --key YOUR_API_KEY
|
|
130
|
+
```
|
|
114
131
|
|
|
132
|
+
Register that command in the tool you use.
|
|
115
133
|
|
|
116
|
-
|
|
134
|
+
#### Cursor
|
|
117
135
|
|
|
118
|
-
|
|
136
|
+
Add this to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (all projects):
|
|
119
137
|
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
---
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"mcpServers": {
|
|
141
|
+
"xkg": {
|
|
142
|
+
"command": "npx",
|
|
143
|
+
"args": ["-y", "mnemos-capture@latest", "serve-mcp", "--key", "YOUR_API_KEY"]
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
131
148
|
|
|
132
|
-
|
|
149
|
+
Or Cursor Settings → MCP → Add new MCP server, same command.
|
|
133
150
|
|
|
134
|
-
|
|
135
|
-
Opaque error messages make every fix a guess. Adding source context to every
|
|
136
|
-
error — which handler, which step, which input — turns debugging from archaeology
|
|
137
|
-
into a directed search.
|
|
151
|
+
#### VS Code
|
|
138
152
|
|
|
139
|
-
|
|
140
|
-
- Every catch block should prefix messages with where it came from
|
|
141
|
-
- "The string did not match the expected pattern" is useless; "[github-write] ..." is actionable
|
|
142
|
-
- Instrument before you fix — opaque errors cause repeated misdiagnoses
|
|
153
|
+
Add this to `.vscode/mcp.json`:
|
|
143
154
|
|
|
144
|
-
|
|
145
|
-
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"servers": {
|
|
158
|
+
"xkg": {
|
|
159
|
+
"command": "npx",
|
|
160
|
+
"args": ["-y", "mnemos-capture@latest", "serve-mcp", "--key", "YOUR_API_KEY"]
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
146
164
|
```
|
|
147
165
|
|
|
148
|
-
|
|
166
|
+
GitHub Copilot Chat in VS Code uses the same file.
|
|
149
167
|
|
|
168
|
+
#### Codex
|
|
150
169
|
|
|
151
|
-
|
|
170
|
+
Codex CLI — add this to `~/.codex/config.toml`:
|
|
152
171
|
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
▼
|
|
158
|
-
┌─────────┐ ┌──────────┐
|
|
159
|
-
│ Inbox │────▶│ Applied │ Insight used — plan executed, rule added, code changed
|
|
160
|
-
└────┬─────┘ └──────────┘
|
|
161
|
-
│
|
|
162
|
-
├──────────▶┌──────────┐
|
|
163
|
-
│ │ Archived │ Reviewed, not actionable right now
|
|
164
|
-
│ └──────────┘
|
|
165
|
-
│
|
|
166
|
-
└──────────▶┌──────────┐
|
|
167
|
-
│ Deleted │ Not useful, permanently removed
|
|
168
|
-
└──────────┘
|
|
172
|
+
```toml
|
|
173
|
+
[mcp_servers.xkg]
|
|
174
|
+
command = "npx"
|
|
175
|
+
args = ["-y", "mnemos-capture@latest", "serve-mcp", "--key", "YOUR_API_KEY"]
|
|
169
176
|
```
|
|
170
177
|
|
|
171
|
-
|
|
178
|
+
Codex App: Settings → MCP → add the same `npx` command.
|
|
172
179
|
|
|
180
|
+
#### Gemini CLI
|
|
173
181
|
|
|
174
|
-
|
|
182
|
+
```bash
|
|
183
|
+
gemini mcp add xkg npx -y mnemos-capture@latest serve-mcp --key YOUR_API_KEY
|
|
184
|
+
```
|
|
175
185
|
|
|
176
|
-
|
|
186
|
+
#### Claude Code
|
|
177
187
|
|
|
178
|
-
```
|
|
179
|
-
|
|
188
|
+
```bash
|
|
189
|
+
claude mcp add xkg -- npx -y mnemos-capture@latest serve-mcp --key YOUR_API_KEY
|
|
180
190
|
```
|
|
181
191
|
|
|
182
|
-
|
|
192
|
+
Or the URL, no API key:
|
|
183
193
|
|
|
184
|
-
|
|
194
|
+
```bash
|
|
195
|
+
claude mcp add --transport http xkg https://mnemos-capture.vercel.app/api/mcp
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Optional session hooks (MCP works without them):
|
|
185
199
|
|
|
186
200
|
```bash
|
|
187
|
-
npx -y mnemos-capture@latest setup-hooks --key
|
|
201
|
+
npx -y mnemos-capture@latest setup-hooks --key YOUR_API_KEY --briefing --vault
|
|
188
202
|
```
|
|
189
203
|
|
|
190
|
-
|
|
204
|
+
Hooks are local files — they run in the CLI and editor extensions, not in the browser.
|
|
205
|
+
|
|
206
|
+
#### Claude Desktop
|
|
191
207
|
|
|
192
|
-
|
|
193
|
-
2. Relevant synthesized rules
|
|
194
|
-
3. A `generate_plan` prompt pre-loaded with the captures to apply
|
|
208
|
+
Settings → Developer → Edit Config. Add the same `npx` block to `claude_desktop_config.json`, then fully restart:
|
|
195
209
|
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"mcpServers": {
|
|
213
|
+
"xkg": {
|
|
214
|
+
"command": "npx",
|
|
215
|
+
"args": ["-y", "mnemos-capture@latest", "serve-mcp", "--key", "YOUR_API_KEY"]
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
196
219
|
```
|
|
197
|
-
3 insights to apply now:
|
|
198
220
|
|
|
199
|
-
|
|
200
|
-
Why: Your current branch rewrites the capture pipeline and all catch blocks are opaque
|
|
201
|
-
Benefit: Every error will identify its source in < 1 line
|
|
221
|
+
#### Anything MCP
|
|
202
222
|
|
|
203
|
-
|
|
223
|
+
If the tool can launch a local process, register the same `npx` command. If it has **custom connectors** instead, paste the URL (that's the [web](#on-the-web) path).
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"mcpServers": {
|
|
228
|
+
"xkg": {
|
|
229
|
+
"command": "npx",
|
|
230
|
+
"args": ["-y", "mnemos-capture@latest", "serve-mcp", "--key", "YOUR_API_KEY"]
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
204
234
|
```
|
|
205
235
|
|
|
206
|
-
|
|
236
|
+
No MCP support yet? Capture in the [xkg app](https://mnemos-capture.vercel.app) and connect later.
|
|
207
237
|
|
|
208
|
-
|
|
238
|
+
## Workflow
|
|
209
239
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
240
|
+
<p align="center">
|
|
241
|
+
<img src="public/flow-workflow.svg" width="720" alt="Docs and notes → Capture → GitHub Markdown → Brief → Plan → Execute → Mark applied" />
|
|
242
|
+
</p>
|
|
213
243
|
|
|
214
|
-
|
|
244
|
+
1. **Capture** — Paste anything text-based: papers, docs, posts, GitHub repos, notes, decisions, ideas, transcripts. xkg detects a URL, a short note, or longer text. No manual tagging.
|
|
215
245
|
|
|
216
|
-
|
|
246
|
+
From a connected worker:
|
|
217
247
|
|
|
218
|
-
|
|
248
|
+
```text
|
|
249
|
+
capture "The Mom Test: don't ask if your idea is good. Ask about the person's real behavior, current workflow, and past spending."
|
|
250
|
+
```
|
|
219
251
|
|
|
220
|
-
|
|
221
|
-
|---|---|
|
|
222
|
-
| Claude Code CLI, VS Code / JetBrains extensions, desktop app | Yes |
|
|
223
|
-
| Claude Code on the web | No — `~/.claude/settings.json` is local only |
|
|
224
|
-
| Cursor / other MCP clients | No — distinct hook systems |
|
|
252
|
+
2. **Brief** — At the start of a work session, ask your worker for a briefing. xkg looks at your project (branch, recent commits, `CLAUDE.md`, repo context) and ranks captures that could help now: **why** it matters, **what** applying it could achieve, **where** it could land. You decide what to apply.
|
|
225
253
|
|
|
226
|
-
|
|
254
|
+
3. **Plan** — Select the captures you want and ask your worker to call `generate_plan`. Each plan is Markdown: codebase mapping, implementation steps with effort tiers (`simple`, `complex`, `architectural`), and a verification checklist.
|
|
227
255
|
|
|
228
|
-
|
|
256
|
+
4. **Execute** — Hand the plan to your worker in the current session, or run it in an isolated git worktree:
|
|
229
257
|
|
|
258
|
+
```bash
|
|
259
|
+
npx -y mnemos-capture@latest config set agent "claude -p"
|
|
260
|
+
npx -y mnemos-capture@latest kos --key YOUR_API_KEY
|
|
261
|
+
```
|
|
230
262
|
|
|
231
|
-
|
|
263
|
+
`kos` creates a worktree, loads the plan as the contract, launches the assistant you configured, and prints the verification checklist when it finishes.
|
|
232
264
|
|
|
233
|
-
|
|
265
|
+
```bash
|
|
266
|
+
npx -y mnemos-capture@latest config set agent "codex exec"
|
|
267
|
+
```
|
|
234
268
|
|
|
235
|
-
###
|
|
269
|
+
### Example capture
|
|
236
270
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
271
|
+
```text
|
|
272
|
+
The Mom Test: don't ask if your idea is good. Ask about the person's real behavior, current workflow, and past spending.
|
|
273
|
+
```
|
|
240
274
|
|
|
241
|
-
|
|
275
|
+
```markdown
|
|
276
|
+
---
|
|
277
|
+
date: 2026-06-05
|
|
278
|
+
source: The Mom Test note
|
|
279
|
+
type: note
|
|
280
|
+
tags: customer-discovery, product, research
|
|
281
|
+
status: inbox
|
|
282
|
+
---
|
|
242
283
|
|
|
243
|
-
|
|
244
|
-
|------|-------------|
|
|
245
|
-
| `list_inbox` | Unprocessed captures with summaries — title, type, tags, core idea. |
|
|
246
|
-
| `search_captures` | Keyword + tag search across inbox, applied, and archived. |
|
|
247
|
-
| `read_capture` | Full Markdown of any capture. |
|
|
248
|
-
| `recall` | Semantic search — describe your task, get the most relevant captures back. More powerful than keyword search. |
|
|
284
|
+
# The Mom Test
|
|
249
285
|
|
|
250
|
-
|
|
286
|
+
## Core idea
|
|
251
287
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
| `archive_capture` | Moves inbox → archived. Reviewed but not actionable now. |
|
|
256
|
-
| `delete_capture` | Permanently removes a capture and its index entry. |
|
|
257
|
-
| `apply_to_context` | Paste task + stack + code snippet → get concrete, file-level suggestions for applying your captured knowledge. |
|
|
288
|
+
Do not ask people to judge your idea. Ask about their real life,
|
|
289
|
+
recent behavior, current workaround, and what they have already
|
|
290
|
+
tried or paid for.
|
|
258
291
|
|
|
259
|
-
|
|
292
|
+
## Key takeaways
|
|
260
293
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
| `generate_plan` | Reads selected captures + optional codebase files → structured Markdown plan with Codebase Mapping table, effort tiers per step, and Verification Checklist. Saved to `plans/`. |
|
|
265
|
-
| `list_plans` | Lists saved plans, or reads a specific plan in full. |
|
|
294
|
+
- Avoid compliments and future promises
|
|
295
|
+
- Ask about specific past behavior
|
|
296
|
+
- Look for existing pain, workarounds, and spending
|
|
266
297
|
|
|
267
|
-
|
|
298
|
+
## Where to apply
|
|
268
299
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
| `get_rules` | Returns synthesized rules — filtered by tag or all. Use to populate `CLAUDE.md` or a system prompt. |
|
|
300
|
+
Discovery interview scripts, landing page tests, and product
|
|
301
|
+
validation prompts.
|
|
302
|
+
```
|
|
273
303
|
|
|
274
|
-
|
|
304
|
+
Plain Markdown in a repo you own. Readable, editable, versioned, portable.
|
|
275
305
|
|
|
276
|
-
|
|
277
|
-
|------|-------------|
|
|
278
|
-
| `curate` | Validates inbox captures: HEAD-checks URLs (404/410 → stale), flags low-confidence extractions. Optional `auto_archive`. Batch cap: 20 files. |
|
|
279
|
-
| `vault_scan` | Scans the full vault for captures relevant to your current activity (score ≥ 0.7). Used by the vault hook. |
|
|
306
|
+
## What's inside
|
|
280
307
|
|
|
308
|
+
You don't have to memorize these. Ask in plain language: "save this", "what do I have on payments?", "brief me for this repo".
|
|
309
|
+
|
|
310
|
+
| Tool | What it does |
|
|
311
|
+
| --- | --- |
|
|
312
|
+
| `capture` | Save new knowledge from pasted text or a URL |
|
|
313
|
+
| `list_inbox` | List captures waiting for review |
|
|
314
|
+
| `search_captures` | Keyword search across your captures |
|
|
315
|
+
| `read_capture` | Read a capture in full |
|
|
316
|
+
| `recall` | Find relevant context from a description of your task |
|
|
317
|
+
| `briefing` | Get project-specific recommendations |
|
|
318
|
+
| `generate_plan` | Turn selected captures into an implementation plan |
|
|
319
|
+
| `list_plans` | List or read saved plans |
|
|
320
|
+
| `apply_capture` | Mark a capture as applied |
|
|
321
|
+
| `archive_capture` | Archive a capture |
|
|
322
|
+
| `delete_capture` | Delete a capture |
|
|
323
|
+
| `apply_to_context` | Get file-level suggestions for the current task |
|
|
324
|
+
| `synthesize` | Combine related captures into reusable rules |
|
|
325
|
+
| `get_rules` | Retrieve those rules |
|
|
326
|
+
| `curate` | Review and clean up captures |
|
|
327
|
+
| `vault_scan` | Find relevant context for what you're about to edit |
|
|
281
328
|
|
|
282
329
|
## CLI
|
|
283
330
|
|
|
331
|
+
No global install required. The binary is **`xkg`** (also `xmu` and `mnemos-capture`). Via npx:
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
npx -y mnemos-capture@latest <command>
|
|
284
335
|
```
|
|
285
|
-
mnemos-capture Open hosted app
|
|
286
|
-
mnemos-capture serve-mcp --key KEY Run local MCP proxy (auto-installs hook)
|
|
287
|
-
mnemos-capture setup-hooks --key KEY [--briefing] [--vault] Install session hooks
|
|
288
|
-
mnemos-capture inbox-check --key KEY [--briefing] Debug what the hook runs
|
|
289
|
-
mnemos-capture vault-check --key KEY Debug what the vault hook runs
|
|
290
|
-
mnemos-capture help Show help
|
|
291
|
-
```
|
|
292
336
|
|
|
293
|
-
|
|
337
|
+
| Command | What it does |
|
|
338
|
+
| --- | --- |
|
|
339
|
+
| `npx -y mnemos-capture@latest` | Open the hosted app |
|
|
340
|
+
| `serve-mcp --key YOUR_API_KEY` | Run the local MCP proxy |
|
|
341
|
+
| `setup-hooks --key YOUR_API_KEY [--briefing] [--vault]` | Install Claude Code hooks |
|
|
342
|
+
| `config set agent "claude -p"` | Set which assistant `kos` should drive |
|
|
343
|
+
| `kos --key YOUR_API_KEY` | Implement the latest plan in an isolated worktree |
|
|
344
|
+
| `inbox-check --key YOUR_API_KEY [--briefing]` | Debug the session hook |
|
|
345
|
+
| `vault-check --key YOUR_API_KEY` | Debug the vault hook |
|
|
346
|
+
| `help` | Show help |
|
|
347
|
+
|
|
348
|
+
## Your context stays in GitHub
|
|
349
|
+
|
|
350
|
+
Captures live as structured Markdown in **your** GitHub repository. Private by default.
|
|
294
351
|
|
|
352
|
+
- **No lock-in** — clone it, move it, delete xkg, keep the files
|
|
353
|
+
- **No proprietary format** — every capture is a readable `.md` file
|
|
354
|
+
- **No training on your data** — captures are sent only to the LLM provider you chose, with the key you supplied, to extract the insight you asked for
|
|
355
|
+
- **Any tool can read it** — anything that reads Git or speaks MCP
|
|
356
|
+
- **BYOK** — your provider, your key, your cost
|
|
357
|
+
- **Never commit your xkg API key** to source control
|
|
295
358
|
|
|
296
|
-
|
|
359
|
+
### What xkg stores, and where
|
|
297
360
|
|
|
298
|
-
|
|
361
|
+
The whole point of this repo being public is that you can check these claims rather than trust them.
|
|
299
362
|
|
|
363
|
+
**Your captures are never stored by xkg.** They are written straight to your own GitHub repo as Markdown (`src/lib/github.ts`). There is no captures table. Delete the app and your knowledge is untouched.
|
|
300
364
|
|
|
301
|
-
|
|
365
|
+
**The database holds only account plumbing** (`src/lib/db.ts`):
|
|
302
366
|
|
|
303
|
-
|
|
367
|
+
| Stored | What it is |
|
|
368
|
+
| --- | --- |
|
|
369
|
+
| `github_id`, `github_username` | who you are |
|
|
370
|
+
| `github_token` | encrypted (`src/lib/crypto.ts`) |
|
|
371
|
+
| `github_repo` | the *name* of your hub, not its contents |
|
|
372
|
+
| `pin_hash` | salted scrypt (`src/lib/pin.ts`) |
|
|
373
|
+
| `api_key` | hashed — not recoverable |
|
|
374
|
+
| `llm_provider`, `llm_api_key` | encrypted |
|
|
375
|
+
| `token_version` | bumped to revoke everything |
|
|
376
|
+
| login attempts, OAuth clients/codes, refresh-token ids | auth plumbing |
|
|
304
377
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
378
|
+
When you capture, the server talks to exactly three kinds of destination:
|
|
379
|
+
|
|
380
|
+
1. **GitHub** — to write the capture into your repo
|
|
381
|
+
2. **Your LLM provider**, with *your* key — Anthropic, OpenAI, or Google
|
|
382
|
+
3. **The page you captured** — if you paste a bare URL, so the model reads real content. Only http/https, never an internal address
|
|
383
|
+
|
|
384
|
+
No analytics, no telemetry, no third-party tracking.
|
|
310
385
|
|
|
386
|
+
### How your credentials are stored
|
|
387
|
+
|
|
388
|
+
| Secret | How it's stored |
|
|
389
|
+
| --- | --- |
|
|
390
|
+
| GitHub token | Encrypted at rest (AES-256-GCM). Uses the `repo` scope, required to read and write a **private** knowledge hub |
|
|
391
|
+
| Your LLM API key | Encrypted at rest (AES-256-GCM) |
|
|
392
|
+
| Your MCP API key | Hashed — never recoverable, not even by xkg |
|
|
393
|
+
| Your PIN | Salted scrypt hash |
|
|
394
|
+
|
|
395
|
+
Your MCP key is shown exactly once. If you lose it, generate a new one.
|
|
396
|
+
|
|
397
|
+
**PIN unlock is device-bound.** It only works on a device that has already signed in with GitHub. A PIN on its own is not enough to reach your account.
|
|
398
|
+
|
|
399
|
+
**Revoking access.** Generating a new MCP key invalidates the old key, every signed-in session, and every connected MCP client. Sessions also expire after 30 days.
|
|
311
400
|
|
|
312
401
|
## Cost
|
|
313
402
|
|
|
314
|
-
|
|
403
|
+
xkg is BYOK. You bring your own API key. xkg never charges you for inference.
|
|
315
404
|
|
|
316
|
-
Extraction runs on a fast, low-cost model (Claude Haiku 4.5 by default)
|
|
405
|
+
Extraction runs on a fast, low-cost model (Claude Haiku 4.5 by default):
|
|
317
406
|
|
|
318
407
|
| Usage | Estimated monthly cost |
|
|
319
|
-
|
|
408
|
+
| --- | --- |
|
|
320
409
|
| 50 captures/month | ~$0.15 |
|
|
321
410
|
| 100 captures/month | ~$0.30 |
|
|
322
411
|
| 200 captures/month | ~$0.60 |
|
|
323
412
|
|
|
324
|
-
Briefing and
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
## Tech stack
|
|
328
|
-
|
|
329
|
-
Next.js · TypeScript · Vercel Postgres · GitHub OAuth · GitHub Content API · MCP protocol · Anthropic SDK · Tailwind CSS · Vitest
|
|
330
|
-
|
|
413
|
+
Briefing, planning, and synthesis only run when you ask for them.
|
|
331
414
|
|
|
332
415
|
## Roadmap
|
|
333
416
|
|
|
334
|
-
-
|
|
335
|
-
- **
|
|
336
|
-
- **Chrome extension** —
|
|
337
|
-
- Voice memo capture
|
|
417
|
+
- **Learning Graph** — Applied work feeds the next brief. The graph compounds.
|
|
418
|
+
- **Knowledge Graph for Teams** — One graph the team and their AI workers share and compound.
|
|
419
|
+
- **Chrome extension** — Capture from the page you are on, without leaving the browser.
|
|
420
|
+
- **Voice memo** — Speak it. xkg turns it into a capture.
|
|
338
421
|
|
|
422
|
+
Working on the code? See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
339
423
|
|
|
340
|
-
##
|
|
341
|
-
|
|
342
|
-
[Sofía Padrón Valdez](https://github.com/Soph20) — builder, AI systems architect.
|
|
424
|
+
## License
|
|
343
425
|
|
|
426
|
+
[MIT License](./LICENSE)
|
|
344
427
|
|
|
345
|
-
|
|
428
|
+
If you use xkg in published work:
|
|
346
429
|
|
|
347
|
-
```
|
|
430
|
+
```bibtex
|
|
348
431
|
@misc{2026mnemos,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
432
|
+
title = {xkg: A Knowledge Graph for AI workers},
|
|
433
|
+
author = {Sofia Padron Valdez},
|
|
434
|
+
year = 2026,
|
|
435
|
+
journal = {GitHub repository},
|
|
436
|
+
publisher = {GitHub},
|
|
437
|
+
howpublished = {\url{https://github.com/Soph20/mnemos-capture}}
|
|
438
|
+
}
|
|
356
439
|
```
|
|
357
|
-
|
|
358
|
-
## License
|
|
359
|
-
|
|
360
|
-
[MIT License - see LICENSE file for details](./LICENSE)
|
package/dist/cli/config.js
CHANGED
|
@@ -1,28 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* optional API key, in ~/.
|
|
4
|
-
*
|
|
2
|
+
* xkg CLI config — stores which AI assistant kos should drive, and an
|
|
3
|
+
* optional API key, in ~/.xkg/config.json.
|
|
4
|
+
* Falls back to ~/.xmu/config.json then ~/.mnemos/config.json.
|
|
5
5
|
*/
|
|
6
6
|
import { homedir } from "os";
|
|
7
7
|
import { join } from "path";
|
|
8
8
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
function xkgDir() {
|
|
10
|
+
return join(homedir(), ".xkg");
|
|
11
|
+
}
|
|
12
|
+
function xmuDir() {
|
|
13
|
+
return join(homedir(), ".xmu");
|
|
14
|
+
}
|
|
15
|
+
function mnemosDir() {
|
|
16
|
+
return join(homedir(), ".mnemos");
|
|
17
|
+
}
|
|
18
|
+
function xkgPath() {
|
|
19
|
+
return join(xkgDir(), "config.json");
|
|
20
|
+
}
|
|
21
|
+
function xmuPath() {
|
|
22
|
+
return join(xmuDir(), "config.json");
|
|
23
|
+
}
|
|
24
|
+
function mnemosPath() {
|
|
25
|
+
return join(mnemosDir(), "config.json");
|
|
26
|
+
}
|
|
27
|
+
/** Path we currently read from: xkg, then xmu, then mnemos. */
|
|
28
|
+
function readPath() {
|
|
29
|
+
if (existsSync(xkgPath()))
|
|
30
|
+
return xkgPath();
|
|
31
|
+
if (existsSync(xmuPath()))
|
|
32
|
+
return xmuPath();
|
|
33
|
+
if (existsSync(mnemosPath()))
|
|
34
|
+
return mnemosPath();
|
|
35
|
+
return xkgPath();
|
|
36
|
+
}
|
|
11
37
|
const ALLOWED_FIELDS = ["agent", "key"];
|
|
12
38
|
export function readConfig() {
|
|
13
|
-
|
|
39
|
+
const path = readPath();
|
|
40
|
+
if (!existsSync(path))
|
|
14
41
|
return {};
|
|
15
42
|
try {
|
|
16
|
-
return JSON.parse(readFileSync(
|
|
43
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
17
44
|
}
|
|
18
45
|
catch {
|
|
19
46
|
return {};
|
|
20
47
|
}
|
|
21
48
|
}
|
|
22
49
|
export function writeConfig(cfg) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
50
|
+
const dir = xkgDir();
|
|
51
|
+
if (!existsSync(dir))
|
|
52
|
+
mkdirSync(dir, { recursive: true });
|
|
53
|
+
writeFileSync(xkgPath(), JSON.stringify(cfg, null, 2) + "\n");
|
|
26
54
|
}
|
|
27
55
|
export function setConfigField(field, value) {
|
|
28
56
|
if (!ALLOWED_FIELDS.includes(field)) {
|
|
@@ -32,21 +60,21 @@ export function setConfigField(field, value) {
|
|
|
32
60
|
cfg[field] = value;
|
|
33
61
|
writeConfig(cfg);
|
|
34
62
|
}
|
|
35
|
-
/** Route `
|
|
63
|
+
/** Route `xkg config <set|get> ...`. */
|
|
36
64
|
export function runConfigCommand(args) {
|
|
37
65
|
const action = args[0];
|
|
38
66
|
if (action === "set") {
|
|
39
67
|
const field = args[1];
|
|
40
68
|
const value = args.slice(2).join(" ");
|
|
41
69
|
if (!field || !value) {
|
|
42
|
-
console.error(
|
|
43
|
-
console.error(' e.g.
|
|
70
|
+
console.error("Usage: xkg config set <field> <value>");
|
|
71
|
+
console.error(' e.g. xkg config set agent "claude -p"');
|
|
44
72
|
process.exit(1);
|
|
45
73
|
}
|
|
46
74
|
try {
|
|
47
75
|
setConfigField(field, value);
|
|
48
76
|
console.log(`Set ${field} = ${value}`);
|
|
49
|
-
console.log(`Saved to ${
|
|
77
|
+
console.log(`Saved to ${xkgPath()}`);
|
|
50
78
|
}
|
|
51
79
|
catch (err) {
|
|
52
80
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -65,6 +93,6 @@ export function runConfigCommand(args) {
|
|
|
65
93
|
}
|
|
66
94
|
return;
|
|
67
95
|
}
|
|
68
|
-
console.error("Usage:
|
|
96
|
+
console.error("Usage: xkg config set|get <field> [value]");
|
|
69
97
|
process.exit(1);
|
|
70
98
|
}
|
package/dist/cli/hooks.js
CHANGED
|
@@ -108,7 +108,7 @@ export function setupHooks(apiKey, opts = {}) {
|
|
|
108
108
|
settings.hooks = { ...hooks, SessionStart: filtered };
|
|
109
109
|
writeSettings(settings);
|
|
110
110
|
if (!opts.silent) {
|
|
111
|
-
console.log("
|
|
111
|
+
console.log("xkg inbox hook installed.");
|
|
112
112
|
console.log(`Location: ${CLAUDE_SETTINGS_PATH}`);
|
|
113
113
|
if (opts.briefing) {
|
|
114
114
|
console.log("At the start of each Claude Code session you'll see a full project briefing.");
|
|
@@ -151,7 +151,7 @@ export function setupPreToolHook(apiKey, opts = {}) {
|
|
|
151
151
|
settings.hooks = { ...hooks, PreToolCall: filtered };
|
|
152
152
|
writeSettings(settings);
|
|
153
153
|
if (!opts.silent) {
|
|
154
|
-
console.log("
|
|
154
|
+
console.log("xkg vault hook installed (PreToolCall).");
|
|
155
155
|
console.log("Your knowledge vault will surface relevant captures as you edit files.");
|
|
156
156
|
}
|
|
157
157
|
}
|
|
@@ -279,7 +279,7 @@ export async function inboxCheck(apiKey, opts = {}) {
|
|
|
279
279
|
process.stdout.write(displayText + "\n");
|
|
280
280
|
if (applyNow.length > 0) {
|
|
281
281
|
const filenames = applyNow.map((s) => `'${s.filename}'`).join(", ");
|
|
282
|
-
process.stdout.write(`\n---\
|
|
282
|
+
process.stdout.write(`\n---\nxkg: ${applyNow.length} insight${applyNow.length === 1 ? "" : "s"} ready to apply now.\n` +
|
|
283
283
|
`Run generate_plan with selected_captures: [${filenames}] to get a full implementation plan.\n`);
|
|
284
284
|
}
|
|
285
285
|
return;
|
|
@@ -294,7 +294,7 @@ export async function inboxCheck(apiKey, opts = {}) {
|
|
|
294
294
|
return;
|
|
295
295
|
const count = parseInt(match[1], 10);
|
|
296
296
|
if (count > 0) {
|
|
297
|
-
process.stdout.write(`
|
|
297
|
+
process.stdout.write(`xkg: ${count} capture${count === 1 ? "" : "s"} in inbox — run list_inbox to review\n`);
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
catch {
|
package/dist/cli/index.js
CHANGED
|
@@ -52,7 +52,7 @@ async function main() {
|
|
|
52
52
|
const keyIdx = args.indexOf("--key");
|
|
53
53
|
const apiKey = keyIdx !== -1 ? args[keyIdx + 1] : readConfig().key;
|
|
54
54
|
if (!apiKey) {
|
|
55
|
-
console.error("No API key. Pass --key YOUR_KEY or store it:
|
|
55
|
+
console.error("No API key. Pass --key YOUR_KEY or store it: xkg config set key YOUR_KEY");
|
|
56
56
|
process.exit(1);
|
|
57
57
|
}
|
|
58
58
|
const planIdx = args.indexOf("--plan");
|
|
@@ -62,13 +62,13 @@ async function main() {
|
|
|
62
62
|
}
|
|
63
63
|
// Default: open the hosted app
|
|
64
64
|
console.log("");
|
|
65
|
-
console.log("
|
|
65
|
+
console.log(" xkg — A knowledge graph for your AI workers\n");
|
|
66
66
|
console.log(` Open ${HOSTED_URL} to start capturing.`);
|
|
67
67
|
console.log("");
|
|
68
68
|
console.log(" First time? Sign in with GitHub — setup takes 30 seconds.");
|
|
69
69
|
console.log("");
|
|
70
|
-
console.log(" Connect
|
|
71
|
-
console.log(" claude mcp add
|
|
70
|
+
console.log(" Connect an AI worker:");
|
|
71
|
+
console.log(" claude mcp add xkg -- npx -y mnemos-capture@latest serve-mcp --key YOUR_API_KEY");
|
|
72
72
|
console.log("");
|
|
73
73
|
// Try to open the URL in the default browser
|
|
74
74
|
const { exec } = await import("child_process");
|
|
@@ -77,31 +77,33 @@ async function main() {
|
|
|
77
77
|
}
|
|
78
78
|
function printHelp() {
|
|
79
79
|
console.log(`
|
|
80
|
-
|
|
80
|
+
xkg — A knowledge graph for your AI workers
|
|
81
81
|
|
|
82
82
|
Usage:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
xkg Open xkg in your browser
|
|
84
|
+
xkg serve-mcp --key KEY Start the MCP server for your AI worker
|
|
85
|
+
xkg setup-hooks --key KEY Install inbox count hook (fast)
|
|
86
|
+
xkg setup-hooks --key KEY --briefing Install full briefing hook (uses LLM)
|
|
87
|
+
xkg setup-hooks --key KEY --vault Install vault hook (PreToolCall)
|
|
88
|
+
xkg setup-hooks --key KEY --briefing --vault Install both hooks
|
|
89
|
+
xkg config set agent "claude -p" Set which AI worker kos drives
|
|
90
|
+
xkg kos --key KEY [--plan FILE] Implement a plan in an isolated worktree
|
|
91
|
+
xkg help Show this help
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
npx -y mnemos-capture@latest … Same CLI, via the published package
|
|
94
|
+
|
|
95
|
+
MCP tools (via your AI worker):
|
|
94
96
|
briefing — Session-start briefing with ranked insights to apply
|
|
95
97
|
generate_plan — Turn selected captures into a full implementation plan
|
|
96
98
|
list_plans — List or read saved implementation plans
|
|
97
99
|
vault_scan — Scan all captures for relevance to current activity
|
|
98
100
|
curate — Validate URLs and flag stale captures
|
|
99
101
|
|
|
100
|
-
kos — implement plans with your own AI
|
|
101
|
-
1. Tell
|
|
102
|
-
|
|
102
|
+
kos — implement plans with your own AI worker (model-agnostic):
|
|
103
|
+
1. Tell xkg which assistant to drive (once):
|
|
104
|
+
xkg config set agent "claude -p" # or "codex exec", "aider --yes --message"
|
|
103
105
|
2. Generate a plan via the generate_plan MCP tool.
|
|
104
|
-
3. Run:
|
|
106
|
+
3. Run: xkg kos --key YOUR_KEY
|
|
105
107
|
kos creates an isolated git worktree, hands the plan to your assistant,
|
|
106
108
|
and reports the branch + the plan's Verification Checklist when done.
|
|
107
109
|
|
|
@@ -112,7 +114,7 @@ function printHelp() {
|
|
|
112
114
|
4. Start capturing!
|
|
113
115
|
|
|
114
116
|
Connect to Claude Code:
|
|
115
|
-
claude mcp add
|
|
117
|
+
claude mcp add xkg -- npx -y mnemos-capture@latest serve-mcp --key YOUR_API_KEY
|
|
116
118
|
|
|
117
119
|
The @latest tag ensures every Claude Code session uses the most recent
|
|
118
120
|
published version. serve-mcp also self-upgrades on startup as a safety net
|
package/dist/cli/kos.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* kos —
|
|
2
|
+
* kos — mnemos' Knowledge Operations orchestrator.
|
|
3
3
|
*
|
|
4
|
-
* Drives whatever AI assistant the user configured (`
|
|
5
|
-
* to implement a generated plan in an isolated git worktree.
|
|
4
|
+
* Drives whatever AI assistant the user configured (`xkg config set agent ...`)
|
|
5
|
+
* to implement a generated plan in an isolated git worktree. mnemos owns the
|
|
6
6
|
* harness-independent parts: fetching the plan, the worktree, and reporting the
|
|
7
7
|
* Verification Checklist. The assistant is a black box — model-agnostic by design.
|
|
8
8
|
*/
|
|
@@ -54,10 +54,10 @@ function run(cmd, cwd) {
|
|
|
54
54
|
export async function kos(apiKey, opts = {}) {
|
|
55
55
|
const cfg = readConfig();
|
|
56
56
|
if (!cfg.agent) {
|
|
57
|
-
console.error("No agent configured. Tell
|
|
58
|
-
console.error('
|
|
59
|
-
console.error('
|
|
60
|
-
console.error('
|
|
57
|
+
console.error("No agent configured. Tell xkg which AI worker to drive:\n");
|
|
58
|
+
console.error(' xkg config set agent "claude -p" # Claude Code');
|
|
59
|
+
console.error(' xkg config set agent "codex exec" # Codex');
|
|
60
|
+
console.error(' xkg config set agent "aider --yes --message" # Aider');
|
|
61
61
|
process.exit(1);
|
|
62
62
|
}
|
|
63
63
|
// 1. Resolve the plan — explicit filename, or the newest saved plan
|
|
@@ -77,7 +77,7 @@ export async function kos(apiKey, opts = {}) {
|
|
|
77
77
|
repoRoot = run("git rev-parse --show-toplevel");
|
|
78
78
|
}
|
|
79
79
|
catch {
|
|
80
|
-
console.error("
|
|
80
|
+
console.error("xkg kos must be run inside a git repository.");
|
|
81
81
|
process.exit(1);
|
|
82
82
|
return;
|
|
83
83
|
}
|
package/dist/cli/mcp-server.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
// MCP server that runs locally via stdio and proxies to the hosted
|
|
2
|
-
// Used by Claude Code: claude mcp add
|
|
3
|
-
const
|
|
1
|
+
// MCP server that runs locally via stdio and proxies to the hosted API.
|
|
2
|
+
// Used by Claude Code: claude mcp add xkg -- npx mnemos-capture serve-mcp --key <api-key>
|
|
3
|
+
const DEFAULT_HOSTED_URL = "https://mnemos-capture.vercel.app/api/mcp";
|
|
4
|
+
/** Override for pointing the proxy at a local instance during development. */
|
|
5
|
+
const HOSTED_URL = process.env.XKG_API_URL ?? process.env.XMU_API_URL ?? process.env.MNEMOS_API_URL ?? DEFAULT_HOSTED_URL;
|
|
4
6
|
function sendMessage(msg) {
|
|
5
7
|
process.stdout.write(`${JSON.stringify(msg)}\n`);
|
|
6
8
|
}
|
|
9
|
+
/** In-flight proxied requests, so shutdown can wait for them. */
|
|
10
|
+
const pending = new Set();
|
|
11
|
+
function rpcError(id, message) {
|
|
12
|
+
sendMessage({ jsonrpc: "2.0", id, error: { code: -32603, message } });
|
|
13
|
+
}
|
|
7
14
|
async function proxyToHosted(apiKey, msg) {
|
|
15
|
+
let res;
|
|
8
16
|
try {
|
|
9
|
-
|
|
17
|
+
res = await fetch(HOSTED_URL, {
|
|
10
18
|
method: "POST",
|
|
11
19
|
headers: {
|
|
12
20
|
"Content-Type": "application/json",
|
|
@@ -14,16 +22,49 @@ async function proxyToHosted(apiKey, msg) {
|
|
|
14
22
|
},
|
|
15
23
|
body: JSON.stringify(msg),
|
|
16
24
|
});
|
|
17
|
-
const data = (await res.json());
|
|
18
|
-
sendMessage(data);
|
|
19
25
|
}
|
|
20
26
|
catch (err) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
const detail = err instanceof Error ? err.message : "unknown error";
|
|
28
|
+
rpcError(msg.id, `Could not reach xkg at ${HOSTED_URL}: ${detail}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const body = await res.text().catch(() => "");
|
|
32
|
+
const result = interpretResponse(res.status, res.headers.get("content-type"), body);
|
|
33
|
+
if ("error" in result) {
|
|
34
|
+
rpcError(msg.id, result.error);
|
|
35
|
+
return;
|
|
26
36
|
}
|
|
37
|
+
sendMessage(result.data);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Turn a raw HTTP reply into either parsed JSON-RPC data or a useful message.
|
|
41
|
+
*
|
|
42
|
+
* Parsing straight to JSON turns any non-JSON reply — an HTML error page from a
|
|
43
|
+
* 500, a proxy block page, a login redirect — into "Unexpected token '<'",
|
|
44
|
+
* which says nothing about what actually happened. Reporting the status and a
|
|
45
|
+
* snippet makes the real cause visible in the MCP client.
|
|
46
|
+
*
|
|
47
|
+
* Exported for testing; this is the logic worth covering, not the stdio plumbing.
|
|
48
|
+
*/
|
|
49
|
+
export function interpretResponse(status, contentType, body) {
|
|
50
|
+
const type = contentType ?? "";
|
|
51
|
+
if (!type.includes("application/json")) {
|
|
52
|
+
const snippet = body.trim().slice(0, 200).replace(/\s+/g, " ");
|
|
53
|
+
return {
|
|
54
|
+
error: `xkg returned a non-JSON response (HTTP ${status}${type ? `, ${type}` : ""})${snippet ? `: ${snippet}` : ""}`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return { data: JSON.parse(body) };
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return { error: `xkg returned malformed JSON (HTTP ${status}).` };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Track a proxied request so shutdown can await it. */
|
|
65
|
+
function track(p) {
|
|
66
|
+
pending.add(p);
|
|
67
|
+
void p.finally(() => pending.delete(p));
|
|
27
68
|
}
|
|
28
69
|
export async function serveMcp() {
|
|
29
70
|
// Parse --key flag
|
|
@@ -31,7 +72,7 @@ export async function serveMcp() {
|
|
|
31
72
|
const keyIdx = args.indexOf("--key");
|
|
32
73
|
const apiKey = keyIdx !== -1 ? args[keyIdx + 1] : undefined;
|
|
33
74
|
if (!apiKey) {
|
|
34
|
-
process.stderr.write("\
|
|
75
|
+
process.stderr.write("\nxkg MCP server requires an API key.\n");
|
|
35
76
|
process.stderr.write("Usage: npx -y mnemos-capture@latest serve-mcp --key <your-api-key>\n\n");
|
|
36
77
|
process.stderr.write("Get your API key at: https://mnemos-capture.vercel.app/onboard\n\n");
|
|
37
78
|
process.exit(1);
|
|
@@ -56,7 +97,7 @@ export async function serveMcp() {
|
|
|
56
97
|
catch {
|
|
57
98
|
// Non-fatal — hook setup should never block the MCP server from starting
|
|
58
99
|
}
|
|
59
|
-
process.stderr.write("
|
|
100
|
+
process.stderr.write("xkg MCP server starting (proxying to hosted instance)...\n");
|
|
60
101
|
let buffer = "";
|
|
61
102
|
process.stdin.setEncoding("utf-8");
|
|
62
103
|
process.stdin.on("data", (chunk) => {
|
|
@@ -72,12 +113,17 @@ export async function serveMcp() {
|
|
|
72
113
|
// Handle notifications/initialized locally (no response needed)
|
|
73
114
|
if (msg.method === "notifications/initialized")
|
|
74
115
|
continue;
|
|
75
|
-
|
|
116
|
+
track(proxyToHosted(apiKey, msg));
|
|
76
117
|
}
|
|
77
118
|
catch {
|
|
78
119
|
process.stderr.write(`Failed to parse: ${line}\n`);
|
|
79
120
|
}
|
|
80
121
|
}
|
|
81
122
|
});
|
|
82
|
-
|
|
123
|
+
// Wait for in-flight requests before exiting: exiting immediately on stdin
|
|
124
|
+
// close discards responses that were still being fetched, so the client sees
|
|
125
|
+
// silence rather than an answer or an error.
|
|
126
|
+
process.stdin.on("end", () => {
|
|
127
|
+
void Promise.allSettled([...pending]).then(() => process.exit(0));
|
|
128
|
+
});
|
|
83
129
|
}
|
|
@@ -59,7 +59,7 @@ export async function maybeSelfUpgrade() {
|
|
|
59
59
|
const latest = await getLatestVersion();
|
|
60
60
|
if (!latest || !isNewer(latest, current))
|
|
61
61
|
return false;
|
|
62
|
-
process.stderr.write(`
|
|
62
|
+
process.stderr.write(`xkg: upgrading to v${latest} (was v${current})...\n`);
|
|
63
63
|
const child = spawn("npx", ["-y", `mnemos-capture@${latest}`, ...process.argv.slice(2)], {
|
|
64
64
|
stdio: "inherit",
|
|
65
65
|
env: { ...process.env, MNEMOS_UPGRADED: "1" },
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mnemos-capture",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "xkg — Turn what you discover into context your AI workers can use. Capture once, then brief, plan, and execute with any MCP-compatible tool.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"mnemos-capture": "./dist/cli/index.js"
|
|
7
|
+
"mnemos-capture": "./dist/cli/index.js",
|
|
8
|
+
"xkg": "./dist/cli/index.js",
|
|
9
|
+
"xmu": "./dist/cli/index.js"
|
|
8
10
|
},
|
|
9
11
|
"scripts": {
|
|
10
12
|
"dev": "next dev",
|
|
@@ -14,10 +16,14 @@
|
|
|
14
16
|
"prepublishOnly": "npm run build:cli",
|
|
15
17
|
"test": "vitest run",
|
|
16
18
|
"test:watch": "vitest",
|
|
17
|
-
"test:e2e": "playwright test"
|
|
19
|
+
"test:e2e": "playwright test",
|
|
20
|
+
"lint": "eslint .",
|
|
21
|
+
"typecheck": "tsc --noEmit"
|
|
18
22
|
},
|
|
19
23
|
"keywords": [
|
|
20
24
|
"ai",
|
|
25
|
+
"xkg",
|
|
26
|
+
"xmu",
|
|
21
27
|
"knowledge",
|
|
22
28
|
"capture",
|
|
23
29
|
"claude",
|
|
@@ -41,24 +47,26 @@
|
|
|
41
47
|
"README.md"
|
|
42
48
|
],
|
|
43
49
|
"dependencies": {
|
|
44
|
-
"@anthropic-ai/sdk": "^0.
|
|
50
|
+
"@anthropic-ai/sdk": "^0.127.0",
|
|
45
51
|
"@vercel/postgres": "^0.10.0",
|
|
46
|
-
"next": "^16.
|
|
47
|
-
"react": "^19.
|
|
48
|
-
"react-dom": "^19.
|
|
52
|
+
"next": "^16.3.5",
|
|
53
|
+
"react": "^19.3.0",
|
|
54
|
+
"react-dom": "^19.3.0"
|
|
49
55
|
},
|
|
50
56
|
"devDependencies": {
|
|
51
|
-
"@playwright/test": "^1.
|
|
52
|
-
"@types/node": "^
|
|
53
|
-
"@types/react": "^19",
|
|
54
|
-
"@types/react-dom": "^19",
|
|
55
|
-
"autoprefixer": "^10.
|
|
57
|
+
"@playwright/test": "^1.62.1",
|
|
58
|
+
"@types/node": "^26",
|
|
59
|
+
"@types/react": "^19.3.0",
|
|
60
|
+
"@types/react-dom": "^19.3.0",
|
|
61
|
+
"autoprefixer": "^10.6.1",
|
|
62
|
+
"eslint": "^9.39.5",
|
|
63
|
+
"eslint-config-next": "^16.3.5",
|
|
56
64
|
"postcss": "^8.5.3",
|
|
57
65
|
"tailwindcss": "^3.4.17",
|
|
58
|
-
"typescript": "^
|
|
59
|
-
"vitest": "^
|
|
66
|
+
"typescript": "^6.0.3",
|
|
67
|
+
"vitest": "^5.0.1"
|
|
60
68
|
},
|
|
61
69
|
"engines": {
|
|
62
|
-
"node": ">=
|
|
70
|
+
"node": ">=20.9"
|
|
63
71
|
}
|
|
64
72
|
}
|