@aisystemresources/emdee 0.2.2 → 0.3.2
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.
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: describe-image
|
|
3
|
+
description: Describe an EMDEE vault image doc and rename it from timestamp to semantic title.
|
|
4
|
+
argument-hint: <vault-path>
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Take the vault doc path from `$ARGUMENTS`. Run the emdee-describe-image skill workflow:
|
|
8
|
+
|
|
9
|
+
1. `emdee get-image --doc-path $ARGUMENTS --remote --out /tmp/emdee-describe.jpg` — save the image locally
|
|
10
|
+
2. Read the image visually and compose:
|
|
11
|
+
- A semantic title, 3-6 words, UPPERCASE-with-HYPHENS (e.g. `HANDSTAND-BALANCE-DRILL`)
|
|
12
|
+
- A one-line summary, 15-30 words
|
|
13
|
+
3. `emdee rename-doc --old-path $ARGUMENTS --new-title <TITLE> --remote`
|
|
14
|
+
4. Get the fresh preamble hash: `emdee get-doc --path <new-path> --remote --json`
|
|
15
|
+
5. `emdee patch-preamble --path <new-path> --body "> <summary>" --expected-hash <hash> --remote`
|
|
16
|
+
|
|
17
|
+
Report the before/after path + title + summary as a punch list at the end.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: summarise
|
|
3
|
+
description: Refresh drifting doc summaries. Optional path prefix argument narrows the batch.
|
|
4
|
+
argument-hint: [path-prefix]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Run the emdee-summariser skill's batch flow:
|
|
8
|
+
|
|
9
|
+
1. `emdee list-summary-drift --remote --limit 20 --format text` (append `--prefix $ARGUMENTS` if the user provided one) → get up to 20 candidate paths
|
|
10
|
+
2. For each path, `emdee get-doc --path <path> --remote --full --format text` → read the body
|
|
11
|
+
3. Compose a fresh summary (15-40 words) that answers "what is this and why does it exist"
|
|
12
|
+
4. Present all proposals as a punch list — do NOT patch yet:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
<path>
|
|
16
|
+
Current: <old blockquote>
|
|
17
|
+
Proposed: <new blockquote>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
5. Wait for the user's approval (per-doc or bulk). On approval:
|
|
21
|
+
- `emdee get-doc --path <path> --remote --json` → fetch preamble.content_hash
|
|
22
|
+
- `emdee patch-preamble --path <path> --body "> <new>" --expected-hash <hash> --remote`
|
|
23
|
+
|
|
24
|
+
Never batch-patch without human review — image content is high-signal but the model can misread ambiguous shots.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vault-status
|
|
3
|
+
description: Show a mini dashboard of the user's EMDEE vault — total docs + top 3 drifting summaries.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Run these commands via the Bash tool and present the results as a compact dashboard:
|
|
7
|
+
|
|
8
|
+
1. `emdee list --remote | wc -l` → total doc count
|
|
9
|
+
2. `emdee list-summary-drift --remote --limit 3 --format text` → top 3 drifting paths
|
|
10
|
+
|
|
11
|
+
Format the output as:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Vault: <N> docs total, <M> with drifting summaries
|
|
15
|
+
Top drift candidates:
|
|
16
|
+
- <path 1>
|
|
17
|
+
- <path 2>
|
|
18
|
+
- <path 3>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If `emdee list --remote` errors with "run login", tell the user to run `emdee login` first and stop.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "emdee",
|
|
3
|
+
"displayName": "Emdee — Local-first knowledge graph",
|
|
4
|
+
"description": "Local-first knowledge graph backed by plain markdown. Bundles the emdee.tech MCP server, the emdee CLI, and 4 Claude Code skills that teach vault conventions + workflows.",
|
|
5
|
+
"version": "0.2.2",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "AI System Resources",
|
|
8
|
+
"url": "https://emdee.tech"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://emdee.tech",
|
|
11
|
+
"repository": "https://github.com/AISystemResources/emdee",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": ["knowledge-graph", "markdown", "vault", "mcp", "claude"],
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"emdee": {
|
|
16
|
+
"type": "http",
|
|
17
|
+
"url": "https://emdee.tech/api/mcp"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"skills": "./skills"
|
|
21
|
+
}
|
package/README.md
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
# Emdee
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A markdown knowledge graph shared by humans and their AI agents. Files you can edit like Obsidian, a vault you can share like Google Drive, and a live MCP endpoint every agent (Claude Code, Claude.ai, Cursor, Codex) reads and writes to natively. One vault, three surfaces — with the plain markdown you wrote as the only source of truth.
|
|
4
4
|
|
|
5
5
|
## Why
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Every knowledge tool picks two of three: human-friendly, team-shareable, agent-native. Notion is human-friendly and shareable, but its blocks aren't markdown and agents can't natively touch them. Obsidian is human-friendly and agent-touchable (they're just markdown files), but private-by-default — sharing is a paid add-on or a git repo. Google Drive is shareable but not markdown-native. Emdee is all three: the markdown a human edits is the exact bytes an agent reads through MCP and a teammate reads through a share link — no hidden index, no parallel summaries, no schema gymnastics. Build up a working journal that survives across sessions and travels with the people you invite in.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
+
**Claude Code plugin (recommended — MCP + CLI + skills in one shot):**
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
claude plugin install @aisystemresources/emdee
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This installs the CLI, wires up the emdee.tech MCP server, and drops in 4 auto-loading skills. Then:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
emdee login # PKCE flow, opens browser
|
|
21
|
+
emdee whoami # confirms your namespace
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Slash commands available after install: `/vault-status`, `/describe-image <path>`, `/summarise [prefix]`.
|
|
25
|
+
|
|
26
|
+
**CLI-only (no plugin, for scripting or non-Claude-Code use):**
|
|
27
|
+
|
|
11
28
|
```bash
|
|
12
29
|
npm install -g @aisystemresources/emdee
|
|
13
30
|
cd ~/my-vault
|
|
@@ -16,6 +33,8 @@ emdee list # your owner + 5 virtual system nodes
|
|
|
16
33
|
emdee mcp # stdio MCP server — point Claude Code at it
|
|
17
34
|
```
|
|
18
35
|
|
|
36
|
+
**claude.ai users:** the plugin doesn't apply (different install model). Use the connect panel on emdee.tech to add the HTTP MCP server directly.
|
|
37
|
+
|
|
19
38
|
## The 5-node OS layer
|
|
20
39
|
|
|
21
40
|
Every Emdee vault has exactly 5 canonical top-level nodes, plus your owner node:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aisystemresources/emdee",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Local-first document management with markdown rendering, knowledge graph, and MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
"src/mcp/",
|
|
37
37
|
"skills/",
|
|
38
38
|
"templates/",
|
|
39
|
+
".claude-plugin/",
|
|
40
|
+
".claude/commands/",
|
|
39
41
|
"README.md"
|
|
40
42
|
],
|
|
41
43
|
"dependencies": {
|
package/src/cli/remote-client.ts
CHANGED
|
@@ -37,6 +37,9 @@ export async function callTool(
|
|
|
37
37
|
method: "POST",
|
|
38
38
|
headers: {
|
|
39
39
|
"Content-Type": "application/json",
|
|
40
|
+
// MCP streamable-HTTP transport requires BOTH content types in Accept
|
|
41
|
+
// or it 406s with "Client must accept both application/json and
|
|
42
|
+
// text/event-stream". We handle whichever shape the server picks below.
|
|
40
43
|
"Accept": "application/json, text/event-stream",
|
|
41
44
|
Authorization: `Bearer ${creds.access_token}`,
|
|
42
45
|
},
|
|
@@ -54,12 +57,33 @@ export async function callTool(
|
|
|
54
57
|
throw new Error(`remote call failed: ${res.status} ${body}`);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
const body =
|
|
60
|
+
const body = await parseJsonRpc(res);
|
|
58
61
|
if (body.error) throw new Error(`remote tool error: ${body.error.message}`);
|
|
59
62
|
if (!body.result) throw new Error("remote call returned no result");
|
|
60
63
|
return body.result;
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
// The MCP streamable-HTTP transport content-negotiates on the request Accept:
|
|
67
|
+
// when the client offers both JSON and SSE (as required — see 406 above),
|
|
68
|
+
// the server may reply with either. JSON we parse directly; SSE arrives as
|
|
69
|
+
// one or more `event: message\ndata: <json>\n\n` frames — for a single
|
|
70
|
+
// tools/call response we take the first `data:` payload.
|
|
71
|
+
async function parseJsonRpc(res: Response): Promise<JsonRpcResponse> {
|
|
72
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
73
|
+
if (ct.includes("text/event-stream")) {
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
const dataLine = text.split(/\r?\n/).find((l) => l.startsWith("data:"));
|
|
76
|
+
if (!dataLine) throw new Error(`remote call returned SSE with no data frame: ${text.slice(0, 200)}`);
|
|
77
|
+
const payload = dataLine.slice("data:".length).trim();
|
|
78
|
+
try {
|
|
79
|
+
return JSON.parse(payload) as JsonRpcResponse;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
throw new Error(`remote call SSE data frame is not valid JSON: ${(e as Error).message}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return (await res.json()) as JsonRpcResponse;
|
|
85
|
+
}
|
|
86
|
+
|
|
63
87
|
/**
|
|
64
88
|
* Convenience: unwrap the MCP text envelope back to a string. Tools that
|
|
65
89
|
* return JSON encode it inside `content[0].text`; tools that return plain
|