dude-claude-plugin 2026.2.1 → 2026.2.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,15 @@
1
+ {
2
+ "name": "dude-claude-plugin",
3
+ "version": "2026.2.1",
4
+ "description": "Ultra-minimal RAG and cross-project memory for Claude CLI",
5
+ "author": { "name": "Fingerskier" },
6
+ "license": "MIT",
7
+ "keywords": ["rag", "memory", "project-context", "issues", "specifications"],
8
+ "hooks": "./hooks.json",
9
+ "mcpServers": {
10
+ "dude": {
11
+ "command": "node",
12
+ "args": ["${CLAUDE_PLUGIN_ROOT}/bin/dude-claude.js", "mcp"]
13
+ }
14
+ }
15
+ }
package/.mcp.json CHANGED
@@ -1,8 +1,8 @@
1
- {
2
- "mcpServers": {
3
- "dude": {
4
- "command": "node",
5
- "args": ["bin/dude-claude.js", "mcp"]
6
- }
7
- }
8
- }
1
+ {
2
+ "mcpServers": {
3
+ "dude": {
4
+ "command": "node",
5
+ "args": ["bin/dude-claude.js", "mcp"]
6
+ }
7
+ }
8
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fingerskier
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 CHANGED
@@ -1,57 +1,80 @@
1
- # Dude Claude Plugin
2
- A context multiplier plug-in for Claude CLI
3
-
4
- ## Install
5
-
6
- ### npx (recommended)
7
-
8
- Add MCP server config to Claude CLI settings (`~/.claude.json` or project `.mcp.json`):
9
-
10
- ```json
11
- {
12
- "mcpServers": {
13
- "dude": {
14
- "command": "npx",
15
- "args": ["dude-claude-plugin", "mcp"]
16
- }
17
- }
18
- }
19
- ```
20
-
21
- ### From source
22
-
23
- 1. Clone the repo
24
- 2. `npm install`
25
- 3. Add MCP server config:
26
- ```json
27
- {
28
- "mcpServers": {
29
- "dude": {
30
- "command": "node",
31
- "args": ["/path/to/dude-claude-plugin/bin/dude-claude.js", "mcp"]
32
- }
33
- }
34
- }
35
- ```
36
- 4. (Optional) Start the web UI: `npm run serve`
37
-
38
- ## Features
39
-
40
- * Local sqlite database~ auto-create
41
- * Save records for each project
42
- * by repo name (for Git)
43
- * by path (for non-Git)
44
- * Each record gets a vector embedding
45
- * Prior to a think
46
- * retrieve relevant records from db via semantic search
47
- * After each think
48
- * If it's a fix upsert associated `issue`record(s)
49
- * if it's an improvement upsert associated `specification` record(s)
50
- * Tools for Claude
51
- * search ~ semantic vector search
52
- * CRUD project
53
- * CRUD issue ~ per project
54
- * CRID specification ~ per project
55
- *
56
- * Local webserver to do manual CRUD
57
-
1
+ # dude-claude-plugin
2
+
3
+ [![npm version](https://img.shields.io/npm/v/dude-claude-plugin.svg)](https://www.npmjs.com/package/dude-claude-plugin)
4
+ [![license](https://img.shields.io/npm/l/dude-claude-plugin.svg)](./LICENSE)
5
+
6
+ Ultra-minimal RAG and cross-project memory for Claude Code.
7
+
8
+ Dude gives Claude a persistent memory across projects. It stores issues and specifications in a local SQLite database with vector embeddings, so Claude automatically recalls relevant context from past sessions.
9
+
10
+ ## Install
11
+
12
+ ### From marketplace (recommended)
13
+
14
+ Installs MCP tools **and** hooks (auto-retrieve on prompt, auto-persist on stop):
15
+
16
+ ```bash
17
+ claude plugin marketplace add fingerskier/claude-plugins
18
+ claude plugin install dude-claude-plugin@fingerskier-plugins
19
+ ```
20
+
21
+ ### MCP server only (via npx)
22
+
23
+ If you just want the 6 MCP tools without auto-hooks:
24
+
25
+ ```bash
26
+ claude mcp add dude -- npx dude-claude-plugin mcp
27
+ ```
28
+
29
+ ### Global install
30
+
31
+ ```bash
32
+ npm install -g dude-claude-plugin
33
+ claude mcp add dude -- dude-claude mcp
34
+ ```
35
+
36
+ ## What it does
37
+
38
+ | Component | Description |
39
+ |-----------|-------------|
40
+ | **MCP server** | 6 tools: `search`, `upsert_record`, `get_record`, `list_records`, `delete_record`, `list_projects` |
41
+ | **Auto-retrieve hook** | On each prompt, searches memory for relevant context and injects it |
42
+ | **Auto-persist hook** | After each response, classifies the work and saves issues/specs |
43
+ | **Web UI** | Local dashboard at `http://127.0.0.1:3456` for manual CRUD |
44
+ | **Storage** | SQLite + sqlite-vec at `~/.dude-claude/dude.db` |
45
+ | **Embeddings** | Local all-MiniLM-L6-v2 via @huggingface/transformers (no API keys) |
46
+
47
+ ## How it works
48
+
49
+ 1. You submit a prompt -- the auto-retrieve hook embeds it and searches for related records across all your projects
50
+ 2. Matching context is injected so Claude has relevant history before reasoning
51
+ 3. After Claude responds, the auto-persist hook classifies the work:
52
+ - Bug fix? Upserts an `issue` record (status: resolved)
53
+ - Improvement? Upserts a `spec` record
54
+ - Neither? Skips silently
55
+ 4. Next session, step 1 finds those records automatically
56
+
57
+ ## Web UI
58
+
59
+ ```bash
60
+ npx dude-claude-plugin serve
61
+ # or if globally installed:
62
+ dude-claude serve
63
+ ```
64
+
65
+ Opens a local dashboard on port 3456 for browsing and editing projects, issues, and specifications.
66
+
67
+ ## Configuration
68
+
69
+ | Env variable | Default | Description |
70
+ |---|---|---|
71
+ | `DUDE_PORT` | `3456` | Web UI port |
72
+ | `DUDE_CONTEXT_LIMIT` | `5` | Max records injected per prompt |
73
+
74
+ ## Requirements
75
+
76
+ - Node.js >= 18
77
+
78
+ ## License
79
+
80
+ [MIT](./LICENSE)
@@ -1,23 +1,23 @@
1
- #!/usr/bin/env node
2
-
3
- const command = process.argv[2] || 'mcp';
4
-
5
- switch (command) {
6
- case 'mcp': {
7
- const { startServer } = await import('../src/server.js');
8
- await startServer();
9
- break;
10
- }
11
- case 'serve': {
12
- const { startWebServer } = await import('../src/web.js');
13
- await startWebServer();
14
- break;
15
- }
16
- default:
17
- console.error(`Usage: dude-claude [mcp|serve]
18
-
19
- Commands:
20
- mcp Start the MCP stdio server (default)
21
- serve Start the web UI server on http://127.0.0.1:${process.env.DUDE_PORT || 3456}`);
22
- process.exit(1);
23
- }
1
+ #!/usr/bin/env node
2
+
3
+ const command = process.argv[2] || 'mcp';
4
+
5
+ switch (command) {
6
+ case 'mcp': {
7
+ const { startServer } = await import('../src/server.js');
8
+ await startServer();
9
+ break;
10
+ }
11
+ case 'serve': {
12
+ const { startWebServer } = await import('../src/web.js');
13
+ await startWebServer();
14
+ break;
15
+ }
16
+ default:
17
+ console.error(`Usage: dude-claude [mcp|serve]
18
+
19
+ Commands:
20
+ mcp Start the MCP stdio server (default)
21
+ serve Start the web UI server on http://127.0.0.1:${process.env.DUDE_PORT || 3456}`);
22
+ process.exit(1);
23
+ }
@@ -1,59 +1,59 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Stop hook — auto-persist records from conversation classification.
5
- * Reads classification JSON from stdin, upserts records as needed.
6
- * On malformed JSON or action=none, exits silently.
7
- */
8
-
9
- import { embed } from '../src/embed.js';
10
- import { initDb, upsertRecord, getCurrentProject } from '../src/db.js';
11
-
12
- try {
13
- const chunks = [];
14
- for await (const chunk of process.stdin) {
15
- chunks.push(chunk);
16
- }
17
- const raw = Buffer.concat(chunks).toString().trim();
18
-
19
- let input;
20
- try {
21
- input = JSON.parse(raw);
22
- } catch {
23
- process.stdout.write('Auto-persist skipped: malformed JSON from classification prompt\n');
24
- process.exit(0);
25
- }
26
-
27
- if (!input.action || input.action === 'none') {
28
- process.exit(0);
29
- }
30
-
31
- if (input.action === 'upsert') {
32
- const kind = input.kind || 'issue';
33
- const title = input.title || 'Untitled';
34
- const body = input.body || '';
35
- const status = input.status || 'open';
36
-
37
- await initDb();
38
- const text = `${title} ${body}`.trim();
39
- const embedding = await embed(text);
40
-
41
- const record = upsertRecord(
42
- {
43
- projectId: getCurrentProject().id,
44
- kind,
45
- title,
46
- body,
47
- status,
48
- },
49
- embedding,
50
- );
51
-
52
- process.stdout.write(`Auto-persisted ${kind}: "${record.title}" (id=${record.id})\n`);
53
- }
54
- } catch (err) {
55
- // Non-blocking: exit cleanly on any error
56
- console.error(`[dude] auto-persist error: ${err.message}`);
57
- process.stdout.write(`Auto-persist skipped: ${err.message}\n`);
58
- process.exit(0);
59
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Stop hook — auto-persist records from conversation classification.
5
+ * Reads classification JSON from stdin, upserts records as needed.
6
+ * On malformed JSON or action=none, exits silently.
7
+ */
8
+
9
+ import { embed } from '../src/embed.js';
10
+ import { initDb, upsertRecord, getCurrentProject } from '../src/db.js';
11
+
12
+ try {
13
+ const chunks = [];
14
+ for await (const chunk of process.stdin) {
15
+ chunks.push(chunk);
16
+ }
17
+ const raw = Buffer.concat(chunks).toString().trim();
18
+
19
+ let input;
20
+ try {
21
+ input = JSON.parse(raw);
22
+ } catch {
23
+ process.stdout.write('Auto-persist skipped: malformed JSON from classification prompt\n');
24
+ process.exit(0);
25
+ }
26
+
27
+ if (!input.action || input.action === 'none') {
28
+ process.exit(0);
29
+ }
30
+
31
+ if (input.action === 'upsert') {
32
+ const kind = input.kind || 'issue';
33
+ const title = input.title || 'Untitled';
34
+ const body = input.body || '';
35
+ const status = input.status || 'open';
36
+
37
+ await initDb();
38
+ const text = `${title} ${body}`.trim();
39
+ const embedding = await embed(text);
40
+
41
+ const record = upsertRecord(
42
+ {
43
+ projectId: getCurrentProject().id,
44
+ kind,
45
+ title,
46
+ body,
47
+ status,
48
+ },
49
+ embedding,
50
+ );
51
+
52
+ process.stdout.write(`Auto-persisted ${kind}: "${record.title}" (id=${record.id})\n`);
53
+ }
54
+ } catch (err) {
55
+ // Non-blocking: exit cleanly on any error
56
+ console.error(`[dude] auto-persist error: ${err.message}`);
57
+ process.stdout.write(`Auto-persist skipped: ${err.message}\n`);
58
+ process.exit(0);
59
+ }
@@ -1,46 +1,46 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * UserPromptSubmit hook — auto-retrieve relevant records.
5
- * Reads the user prompt from stdin JSON, embeds it, searches the DB,
6
- * and writes formatted context to stdout for Claude to see.
7
- */
8
-
9
- import { embed } from '../src/embed.js';
10
- import { initDb, searchRecords } from '../src/db.js';
11
-
12
- try {
13
- const chunks = [];
14
- for await (const chunk of process.stdin) {
15
- chunks.push(chunk);
16
- }
17
- const input = JSON.parse(Buffer.concat(chunks).toString());
18
- const prompt = input.prompt || input.tool_input?.prompt || '';
19
-
20
- if (!prompt.trim()) {
21
- process.exit(0);
22
- }
23
-
24
- await initDb();
25
- const embedding = await embed(prompt);
26
- const limit = Number(process.env.DUDE_CONTEXT_LIMIT) || 5;
27
- const results = searchRecords(embedding, { limit });
28
-
29
- if (results.length === 0) {
30
- process.exit(0);
31
- }
32
-
33
- // Format context for Claude
34
- const lines = ['[dude] Relevant context from memory:\n'];
35
- for (const r of results) {
36
- lines.push(`- [${r.kind}] ${r.title} (project: ${r.project}, status: ${r.status}, similarity: ${r.similarity.toFixed(2)})`);
37
- if (r.body) {
38
- lines.push(` ${r.body.slice(0, 200)}${r.body.length > 200 ? '…' : ''}`);
39
- }
40
- }
41
- process.stdout.write(lines.join('\n') + '\n');
42
- } catch (err) {
43
- // Non-blocking: exit cleanly on any error
44
- console.error(`[dude] auto-retrieve error: ${err.message}`);
45
- process.exit(0);
46
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * UserPromptSubmit hook — auto-retrieve relevant records.
5
+ * Reads the user prompt from stdin JSON, embeds it, searches the DB,
6
+ * and writes formatted context to stdout for Claude to see.
7
+ */
8
+
9
+ import { embed } from '../src/embed.js';
10
+ import { initDb, searchRecords } from '../src/db.js';
11
+
12
+ try {
13
+ const chunks = [];
14
+ for await (const chunk of process.stdin) {
15
+ chunks.push(chunk);
16
+ }
17
+ const input = JSON.parse(Buffer.concat(chunks).toString());
18
+ const prompt = input.prompt || input.tool_input?.prompt || '';
19
+
20
+ if (!prompt.trim()) {
21
+ process.exit(0);
22
+ }
23
+
24
+ await initDb();
25
+ const embedding = await embed(prompt);
26
+ const limit = Number(process.env.DUDE_CONTEXT_LIMIT) || 5;
27
+ const results = searchRecords(embedding, { limit });
28
+
29
+ if (results.length === 0) {
30
+ process.exit(0);
31
+ }
32
+
33
+ // Format context for Claude
34
+ const lines = ['[dude] Relevant context from memory:\n'];
35
+ for (const r of results) {
36
+ lines.push(`- [${r.kind}] ${r.title} (project: ${r.project}, status: ${r.status}, similarity: ${r.similarity.toFixed(2)})`);
37
+ if (r.body) {
38
+ lines.push(` ${r.body.slice(0, 200)}${r.body.length > 200 ? '…' : ''}`);
39
+ }
40
+ }
41
+ process.stdout.write(lines.join('\n') + '\n');
42
+ } catch (err) {
43
+ // Non-blocking: exit cleanly on any error
44
+ console.error(`[dude] auto-retrieve error: ${err.message}`);
45
+ process.exit(0);
46
+ }
package/hooks.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "hooks": {
3
+ "UserPromptSubmit": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/auto-retrieve.js",
9
+ "timeout": 30
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "Stop": [
15
+ {
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/auto-persist.js",
20
+ "timeout": 30
21
+ }
22
+ ]
23
+ }
24
+ ]
25
+ }
26
+ }
package/package.json CHANGED
@@ -1,24 +1,52 @@
1
- {
2
- "name": "dude-claude-plugin",
3
- "version": "2026.2.1",
4
- "description": "Ultra-minimal RAG and cross-project memory for Claude CLI",
5
- "type": "module",
6
- "bin": {
7
- "dude-claude": "bin/dude-claude.js"
8
- },
9
- "engines": {
10
- "node": ">=18"
11
- },
12
- "scripts": {
13
- "start": "node bin/dude-claude.js mcp",
14
- "serve": "node bin/dude-claude.js serve"
15
- },
16
- "dependencies": {
17
- "@modelcontextprotocol/sdk": "^1.12.1",
18
- "zod": "^3.24.2",
19
- "better-sqlite3": "^11.8.1",
20
- "sqlite-vec": "^0.1.6",
21
- "@huggingface/transformers": "^3.4.1"
22
- },
23
- "license": "MIT"
24
- }
1
+ {
2
+ "name": "dude-claude-plugin",
3
+ "version": "2026.2.2",
4
+ "description": "Ultra-minimal RAG and cross-project memory for Claude CLI",
5
+ "type": "module",
6
+ "bin": {
7
+ "dude-claude": "bin/dude-claude.js"
8
+ },
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
12
+ "scripts": {
13
+ "start": "node bin/dude-claude.js mcp",
14
+ "serve": "node bin/dude-claude.js serve"
15
+ },
16
+ "keywords": [
17
+ "claude",
18
+ "claude-code",
19
+ "plugin",
20
+ "mcp",
21
+ "rag",
22
+ "memory",
23
+ "knowledge-base",
24
+ "vector-search"
25
+ ],
26
+ "author": "Fingerskier",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/fingerskier/dude-claude-plugin.git"
30
+ },
31
+ "homepage": "https://github.com/fingerskier/dude-claude-plugin#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/fingerskier/dude-claude-plugin/issues"
34
+ },
35
+ "files": [
36
+ "bin/",
37
+ "src/",
38
+ "hooks/",
39
+ "web/",
40
+ ".claude-plugin/",
41
+ ".mcp.json",
42
+ "hooks.json"
43
+ ],
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.12.1",
46
+ "zod": "^3.24.2",
47
+ "better-sqlite3": "^11.8.1",
48
+ "sqlite-vec": "^0.1.6",
49
+ "@huggingface/transformers": "^3.4.1"
50
+ },
51
+ "license": "MIT"
52
+ }