kyp-mem 0.2.0 → 0.2.1

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 CHANGED
@@ -1,21 +1,27 @@
1
1
  # KYP-MEM — Know Your Project Memory
2
2
 
3
- **Headless Obsidian for AI agents.** A markdown knowledge base with wikilinks, backlinks, tags, related notes, and a neon web UI — all powered by an MCP server so Claude (or any AI) can read and write your project knowledge directly.
3
+ **Headless knowledge base for AI agents.** Markdown notes with wikilinks, backlinks, tags, related notes, and a neon web UI — all powered by an MCP server so Claude (or any AI) can read and write your project knowledge directly.
4
4
 
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- pip install kyp-mem
8
+ npx -y kyp-mem
9
+ ```
10
+
11
+ Or install the command globally:
12
+
13
+ ```bash
14
+ npm install -g kyp-mem
9
15
  ```
10
16
 
11
17
  ## Setup (3 commands)
12
18
 
13
19
  ```bash
14
20
  # 1. Choose where your vault (knowledge base) lives
15
- kyp-mem init
21
+ npx -y kyp-mem init
16
22
 
17
23
  # 2. Connect to Claude Code — auto-configures MCP
18
- kyp-mem setup-claude
24
+ npx -y kyp-mem setup-claude
19
25
 
20
26
  # 3. Restart Claude Code — done!
21
27
  # kyp-mem now runs headlessly every session.
@@ -27,10 +33,10 @@ That's it. Claude now has `kyp_read`, `kyp_write`, `kyp_search`, and 7 other too
27
33
  ## Optional: Web UI
28
34
 
29
35
  ```bash
30
- kyp-mem ui
36
+ npx -y kyp-mem ui
31
37
  ```
32
38
 
33
- Opens an Obsidian-like interface at `localhost:3333` with:
39
+ Opens a rich interface at `localhost:3333` with:
34
40
  - Collapsible folder tree
35
41
  - Rendered markdown with syntax highlighting
36
42
  - Clickable `[[wikilinks]]`
@@ -50,7 +56,7 @@ Opens an Obsidian-like interface at `localhost:3333` with:
50
56
  ```
51
57
 
52
58
  - **Headless by default** — runs as an MCP server (stdio), no GUI needed
53
- - **Markdown files on disk** — same format as Obsidian, no database
59
+ - **Markdown files on disk** — plain `.md` files with YAML frontmatter, no database
54
60
  - **In-memory index** — links, backlinks, tags, search, similarity scoring
55
61
  - **Web UI optional** — `kyp-mem ui` when you want to browse visually
56
62
 
@@ -83,7 +89,7 @@ Opens an Obsidian-like interface at `localhost:3333` with:
83
89
 
84
90
  ## Note Format
85
91
 
86
- Standard markdown with YAML frontmatter — same as Obsidian:
92
+ Standard markdown with YAML frontmatter:
87
93
 
88
94
  ```markdown
89
95
  ---
@@ -108,8 +114,8 @@ If you prefer to configure manually instead of using `setup-claude`:
108
114
  {
109
115
  "mcpServers": {
110
116
  "kyp-mem": {
111
- "command": "kyp-mem",
112
- "args": ["serve"],
117
+ "command": "npx",
118
+ "args": ["-y", "kyp-mem", "serve"],
113
119
  "env": {
114
120
  "KYP_VAULT": "~/.kyp-mem/vault"
115
121
  }
@@ -134,12 +140,10 @@ Add to `~/.claude/settings.json` (global) or `.claude/settings.json` (per-projec
134
140
  └── ...
135
141
  ```
136
142
 
137
- ## Publishing to PyPI
143
+ ## Publishing to npm
138
144
 
139
145
  ```bash
140
- pip install build twine
141
- python3 -m build
142
- twine upload dist/*
146
+ npm publish
143
147
  ```
144
148
 
145
149
  ## License
package/bin/cli.mjs CHANGED
@@ -1,33 +1,68 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { execFileSync, execSync } from "child_process";
3
+ import { spawnSync } from "child_process";
4
+ import { delimiter, dirname, resolve } from "path";
5
+ import { fileURLToPath } from "url";
4
6
 
5
7
  const args = process.argv.slice(2);
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const root = resolve(__dirname, "..");
6
10
 
7
- function tryRun(cmd, cmdArgs) {
8
- try {
9
- execFileSync(cmd, cmdArgs, { stdio: "inherit" });
10
- return true;
11
- } catch {
12
- return false;
11
+ const env = {
12
+ ...process.env,
13
+ PYTHONPATH: process.env.PYTHONPATH
14
+ ? `${root}${delimiter}${process.env.PYTHONPATH}`
15
+ : root,
16
+ };
17
+
18
+ function run(command, cmdArgs, stdio = "ignore") {
19
+ return spawnSync(command, cmdArgs, { stdio, env });
20
+ }
21
+
22
+ function pythonCandidates() {
23
+ if (process.env.KYP_MEM_PYTHON) {
24
+ return [[process.env.KYP_MEM_PYTHON, []]];
25
+ }
26
+
27
+ const candidates = [
28
+ ["python3", []],
29
+ ["python", []],
30
+ ];
31
+
32
+ if (process.platform === "win32") {
33
+ candidates.unshift(["py", ["-3"]]);
34
+ }
35
+
36
+ return candidates;
37
+ }
38
+
39
+ function findPython() {
40
+ for (const [command, prefixArgs] of pythonCandidates()) {
41
+ const result = run(command, [...prefixArgs, "--version"]);
42
+ if (result.status === 0) {
43
+ return [command, prefixArgs];
44
+ }
13
45
  }
46
+
47
+ return null;
14
48
  }
15
49
 
16
- // Try the installed kyp-mem binary first
17
- if (tryRun("kyp-mem", args)) process.exit(0);
50
+ const python = findPython();
18
51
 
19
- // Fallback: python3 -m kyp_mem.cli
20
- if (tryRun("python3", ["-m", "kyp_mem.cli", ...args])) process.exit(0);
52
+ if (python) {
53
+ const [command, prefixArgs] = python;
54
+ const result = run(command, [...prefixArgs, "-m", "kyp_mem.cli", ...args], "inherit");
21
55
 
22
- // Fallback: python -m kyp_mem.cli
23
- if (tryRun("python", ["-m", "kyp_mem.cli", ...args])) process.exit(0);
56
+ if (result.signal) {
57
+ process.kill(process.pid, result.signal);
58
+ }
59
+
60
+ process.exit(result.status ?? 1);
61
+ }
24
62
 
25
63
  console.error("");
26
- console.error(" \x1b[31mError:\x1b[0m kyp-mem Python package not found.");
64
+ console.error(" \x1b[31mError:\x1b[0m Python 3 was not found.");
27
65
  console.error("");
28
- console.error(" Install it:");
29
- console.error(" \x1b[33mpip install kyp-mem\x1b[0m");
30
- console.error(" Or from source:");
31
- console.error(" \x1b[33mpip install git+https://github.com/Adhithya-Karthikeyan/KYP-MEM.git\x1b[0m");
66
+ console.error(" Install Python 3.10+ and rerun this command.");
32
67
  console.error("");
33
68
  process.exit(1);
package/bin/install.mjs CHANGED
@@ -1,36 +1,77 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { execSync } from "child_process";
3
+ import { spawnSync } from "child_process";
4
4
  import { fileURLToPath } from "url";
5
5
  import { dirname, resolve } from "path";
6
6
 
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
8
  const root = resolve(__dirname, "..");
9
9
 
10
- function tryInstall(cmd) {
11
- try {
12
- execSync(cmd, { cwd: root, stdio: "pipe" });
13
- return true;
14
- } catch {
15
- return false;
10
+ function run(command, args, options = {}) {
11
+ return spawnSync(command, args, {
12
+ cwd: root,
13
+ stdio: options.stdio ?? "ignore",
14
+ env: {
15
+ ...process.env,
16
+ PIP_DISABLE_PIP_VERSION_CHECK: "1",
17
+ },
18
+ });
19
+ }
20
+
21
+ function pythonCandidates() {
22
+ if (process.env.KYP_MEM_PYTHON) {
23
+ return [[process.env.KYP_MEM_PYTHON, []]];
24
+ }
25
+
26
+ const candidates = [
27
+ ["python3", []],
28
+ ["python", []],
29
+ ];
30
+
31
+ if (process.platform === "win32") {
32
+ candidates.unshift(["py", ["-3"]]);
16
33
  }
34
+
35
+ return candidates;
36
+ }
37
+
38
+ function findPython() {
39
+ for (const [command, prefixArgs] of pythonCandidates()) {
40
+ const result = run(command, [...prefixArgs, "--version"]);
41
+ if (result.status === 0) {
42
+ return [command, prefixArgs];
43
+ }
44
+ }
45
+
46
+ return null;
17
47
  }
18
48
 
19
- // Check if already installed
20
- try {
21
- execSync("kyp-mem --help", { stdio: "pipe" });
49
+ if (process.env.KYP_MEM_SKIP_PYTHON_INSTALL === "1") {
22
50
  process.exit(0);
23
- } catch {}
51
+ }
52
+
53
+ const python = findPython();
54
+
55
+ if (!python) {
56
+ console.log(" \x1b[33m!\x1b[0m Python 3 was not found.");
57
+ console.log(" \x1b[33m!\x1b[0m Install Python 3.10+ and run: python3 -m pip install --user .");
58
+ process.exit(0);
59
+ }
60
+
61
+ const [pythonCommand, pythonPrefixArgs] = python;
24
62
 
25
63
  console.log(" Installing kyp-mem Python package...");
26
64
 
27
- if (tryInstall("pip install --user .")) {
28
- console.log(" \x1b[32m✓\x1b[0m kyp-mem installed successfully");
29
- } else if (tryInstall("pip3 install --user .")) {
30
- console.log(" \x1b[32m✓\x1b[0m kyp-mem installed successfully");
31
- } else if (tryInstall("python3 -m pip install --user .")) {
65
+ const result = run(
66
+ pythonCommand,
67
+ [...pythonPrefixArgs, "-m", "pip", "install", "--user", "."],
68
+ { stdio: "inherit" },
69
+ );
70
+
71
+ if (result.status === 0) {
32
72
  console.log(" \x1b[32m✓\x1b[0m kyp-mem installed successfully");
33
73
  } else {
34
- console.log(" \x1b[33m!\x1b[0m Could not auto-install Python package.");
35
- console.log(" \x1b[33m!\x1b[0m Run manually: pip install kyp-mem");
74
+ console.log(" \x1b[33m!\x1b[0m Could not auto-install the Python package.");
75
+ console.log(` \x1b[33m!\x1b[0m Run manually from ${root}:`);
76
+ console.log(" python3 -m pip install --user .");
36
77
  }
@@ -1,3 +1,3 @@
1
- """KYP-MEM — Know Your Project Memory. Headless Obsidian for AI agents."""
1
+ """KYP-MEM — Know Your Project Memory. Headless knowledge base for AI agents."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.1"
package/kyp_mem/cli.py CHANGED
@@ -16,7 +16,7 @@ R = "\033[0m" # reset
16
16
  def main():
17
17
  parser = argparse.ArgumentParser(
18
18
  prog="kyp-mem",
19
- description="KYP-MEM — Know Your Project Memory. Headless Obsidian for AI agents.",
19
+ description="KYP-MEM — Know Your Project Memory. Headless knowledge base for AI agents.",
20
20
  )
21
21
  parser.add_argument("--vault", default=None, help="Override vault path")
22
22
 
@@ -74,7 +74,7 @@ def _run_init():
74
74
  print(f"{C} ██║ ██╗ ██║ ██║ ██║ ╚═╝ ██║███████╗██║ ╚═╝ ██║{R}")
75
75
  print(f"{C} ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝{R}")
76
76
  print()
77
- print(f" {D}Know Your Project — Headless Obsidian for AI agents{R}")
77
+ print(f" {D}Know Your Project — Headless knowledge base for AI agents{R}")
78
78
  print()
79
79
  print(f" {Y}>> First-time setup{R}")
80
80
  print()
@@ -108,12 +108,20 @@ def _run_setup_claude(global_config: bool = False):
108
108
 
109
109
  vault_path = get_vault_path()
110
110
  kyp_mem_bin = shutil.which("kyp-mem")
111
-
112
- if not kyp_mem_bin:
111
+ npx_bin = shutil.which("npx")
112
+
113
+ if kyp_mem_bin and "_npx" not in Path(kyp_mem_bin).parts:
114
+ mcp_command = kyp_mem_bin
115
+ mcp_args = ["serve"]
116
+ elif npx_bin:
117
+ mcp_command = npx_bin
118
+ mcp_args = ["-y", "kyp-mem", "serve"]
119
+ else:
113
120
  print(f" {Y}Warning:{R} 'kyp-mem' not found in PATH.")
114
- print(f" {D}Make sure you installed with: pip install kyp-mem{R}")
121
+ print(f" {D}Make sure you installed with: npm install -g kyp-mem{R}")
115
122
  print()
116
- kyp_mem_bin = "kyp-mem"
123
+ mcp_command = "kyp-mem"
124
+ mcp_args = ["serve"]
117
125
 
118
126
  if global_config:
119
127
  settings_path = Path.home() / ".claude" / "settings.json"
@@ -134,8 +142,8 @@ def _run_setup_claude(global_config: bool = False):
134
142
  mcp_servers = settings.setdefault("mcpServers", {})
135
143
 
136
144
  mcp_servers["kyp-mem"] = {
137
- "command": kyp_mem_bin,
138
- "args": ["serve"],
145
+ "command": mcp_command,
146
+ "args": mcp_args,
139
147
  "env": {
140
148
  "KYP_VAULT": vault_path,
141
149
  },
@@ -148,7 +156,7 @@ def _run_setup_claude(global_config: bool = False):
148
156
  print()
149
157
  print(f" {G}✓{R} MCP server added to {scope} settings")
150
158
  print(f" {D} File: {settings_path}{R}")
151
- print(f" {D} Command: {kyp_mem_bin} serve{R}")
159
+ print(f" {D} Command: {mcp_command} {' '.join(mcp_args)}{R}")
152
160
  print(f" {D} Vault: {vault_path}{R}")
153
161
  print()
154
162
  print(f" {C}Done!{R} Restart Claude Code and kyp-mem will run automatically.")
@@ -243,7 +251,7 @@ def _run_doctor():
243
251
  def _print_banner():
244
252
  print()
245
253
  print(f"{C} KYP-MEM{R} — Know Your Project Memory")
246
- print(f" {D}Headless Obsidian for AI agents{R}")
254
+ print(f" {D}Headless knowledge base for AI agents{R}")
247
255
  print()
248
256
 
249
257
 
package/kyp_mem/server.py CHANGED
@@ -7,7 +7,7 @@ from .vault import Vault
7
7
 
8
8
  vault = Vault(get_vault_path())
9
9
 
10
- mcp = FastMCP("kyp-mem", description="Know Your Project — headless knowledge base like Obsidian")
10
+ mcp = FastMCP("kyp-mem", description="Know Your Project — headless knowledge base for AI agents")
11
11
 
12
12
 
13
13
  @mcp.tool()
package/kyp_mem/ui.py CHANGED
@@ -1,4 +1,4 @@
1
- """KYP-MEM web UI — Obsidian-like interface for browsing the vault."""
1
+ """KYP-MEM web UI — interactive interface for browsing the vault."""
2
2
 
3
3
  import webbrowser
4
4
  from pathlib import Path
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "kyp-mem",
3
- "version": "0.2.0",
4
- "description": "Know Your Project — Headless Obsidian for AI agents. MCP-powered knowledge base with neon web UI.",
3
+ "version": "0.2.1",
4
+ "description": "Know Your Project — Headless knowledge base for AI agents. MCP-powered with wikilinks, backlinks, and neon web UI.",
5
5
  "bin": {
6
- "kyp-mem": "./bin/cli.mjs"
6
+ "kyp-mem": "bin/cli.mjs"
7
7
  },
8
8
  "files": [
9
9
  "bin/",
10
- "kyp_mem/",
10
+ "kyp_mem/*.py",
11
+ "kyp_mem/static/",
11
12
  "pyproject.toml",
12
13
  "README.md",
13
14
  "LICENSE"
@@ -17,7 +18,7 @@
17
18
  },
18
19
  "keywords": [
19
20
  "knowledge-base",
20
- "obsidian",
21
+ "markdown",
21
22
  "ai",
22
23
  "mcp",
23
24
  "claude",
@@ -29,7 +30,7 @@
29
30
  "license": "MIT",
30
31
  "repository": {
31
32
  "type": "git",
32
- "url": "https://github.com/Adhithya-Karthikeyan/KYP-MEM.git"
33
+ "url": "git+https://github.com/Adhithya-Karthikeyan/KYP-MEM.git"
33
34
  },
34
35
  "homepage": "https://github.com/Adhithya-Karthikeyan/KYP-MEM"
35
36
  }
package/pyproject.toml CHANGED
@@ -4,15 +4,15 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "kyp-mem"
7
- version = "0.2.0"
8
- description = "Know Your Project — Headless Obsidian for AI agents. MCP-powered knowledge base with neon web UI."
7
+ version = "0.2.1"
8
+ description = "Know Your Project — Headless knowledge base for AI agents. MCP-powered with wikilinks, backlinks, and neon web UI."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
11
11
  requires-python = ">=3.10"
12
12
  authors = [
13
- {name = "KDB AI Agency", email = "dfreakhitman@gmail.com"}
13
+ {name = "KDB AI Agency", email = "skadhithya95@gmail.com"}
14
14
  ]
15
- keywords = ["knowledge-base", "obsidian", "ai", "mcp", "notes", "wiki", "second-brain"]
15
+ keywords = ["knowledge-base", "markdown", "ai", "mcp", "notes", "wiki", "second-brain"]
16
16
  classifiers = [
17
17
  "Development Status :: 3 - Alpha",
18
18
  "Intended Audience :: Developers",