@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
- Local-first knowledge graph backed by plain markdown. Humans browse it through a Next.js renderer; agents (Claude Code, Claude.ai, Cursor, Codex) read and write the same files through an MCP server. The vault is the source of truth anything an LLM says traces back to a file you wrote.
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
- LLM agents need a stable, human-readable substrate to read and write their own context over time. Most knowledge-graph tools are either built for humans (Obsidian) or built for agents (vector stores). Emdee is a single substrate for both: the markdown a human edits is the exact bytes an agent reads, with no hidden index, no parallel summaries, no schema gymnastics. Build up a working journal that survives across sessions.
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.2.2",
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": {
@@ -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 = (await res.json()) as JsonRpcResponse;
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