@heretek-ai/epistemic-swarm 0.2.0 → 0.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.
Files changed (42) hide show
  1. package/.claude-plugin/marketplace.json +36 -9
  2. package/.claude-plugin/plugin.json +47 -41
  3. package/MARKETPLACE.md +93 -0
  4. package/README.md +39 -2
  5. package/bin/cli.js +58 -0
  6. package/config/mcp_launcher.py +215 -0
  7. package/hooks/hooks.json +24 -0
  8. package/package.json +26 -3
  9. package/plugins/research-cache/.claude-plugin/plugin.json +15 -0
  10. package/plugins/socratic-grilling/.claude-plugin/plugin.json +15 -0
  11. package/plugins/socratic-grilling/skills/grilling/SKILL.md +48 -0
  12. package/plugins/socratic-grilling/skills/grilling/__init__.py +0 -0
  13. package/plugins/socratic-grilling/skills/grilling/socratic_tree.py +148 -0
  14. package/prompts/agent_code_auditor.md +88 -0
  15. package/prompts/agent_oss_scout.md +78 -0
  16. package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
  17. package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
  18. package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
  19. package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
  20. package/runner/research_swarm.py +230 -81
  21. package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
  22. package/runner/tests/test_swarm.py +37 -0
  23. package/skills/code_audit/SKILL.md +45 -0
  24. package/skills/epistemic_search/SKILL.md +35 -0
  25. package/skills/epistemic_search/__init__.py +1 -0
  26. package/skills/epistemic_search/scripts/fetch.py +157 -0
  27. package/skills/epistemic_search/scripts/search.py +162 -0
  28. package/skills/oss_scout/SKILL.md +49 -0
  29. package/skills/research_cache/SKILL.md +36 -0
  30. package/skills/research_cache/__init__.py +0 -0
  31. package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
  32. package/skills/{research-cache → research_cache}/__pycache__/hasher.cpython-311.pyc +0 -0
  33. package/skills/research_cache/hasher.py +195 -0
  34. package/skills/swarm_config/SKILL.md +72 -0
  35. package/skills/swarm_config/__init__.py +4 -0
  36. package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
  37. package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
  38. package/skills/swarm_config/configure.py +167 -0
  39. package/skills/research-cache/__pycache__/__init__.cpython-311.pyc +0 -0
  40. /package/{skills/research-cache → plugins/research-cache/skills/research_cache}/SKILL.md +0 -0
  41. /package/{skills/research-cache → plugins/research-cache/skills/research_cache}/__init__.py +0 -0
  42. /package/{skills/research-cache → plugins/research-cache/skills/research_cache}/hasher.py +0 -0
@@ -1,14 +1,41 @@
1
1
  {
2
+ "$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
2
3
  "name": "heretek-official",
3
- "owner": "Heretek AI",
4
- "description": "Official plugins and agent harnesses from Heretek AI",
5
- "plugins": {
6
- "epistemic-swarm": {
7
- "source": {
8
- "source": "github",
9
- "repo": "Heretek-AI/IUMBTEMS"
4
+ "description": "Official high-integrity research agents and epistemic skills from Heretek AI",
5
+ "owner": {
6
+ "name": "Heretek AI",
7
+ "email": "dev@heretek.ai"
8
+ },
9
+ "plugins": [
10
+ {
11
+ "name": "epistemic-swarm",
12
+ "description": "High-Integrity Dialectic Research Agent Harness enforcing verified empirical evidence over parametric hallucination.",
13
+ "author": {
14
+ "name": "Heretek AI"
10
15
  },
11
- "description": "High-Integrity Dialectic Research Agent Harness for Claude Code"
16
+ "category": "research",
17
+ "source": "./",
18
+ "homepage": "https://github.com/Heretek-AI/IUMBTEMS"
19
+ },
20
+ {
21
+ "name": "socratic-grilling",
22
+ "description": "Matt Pocock-style Socratic interrogation, premise inversion, and lateral exploration skill for Claude Code.",
23
+ "author": {
24
+ "name": "Heretek AI"
25
+ },
26
+ "category": "agents",
27
+ "source": "./plugins/socratic-grilling",
28
+ "homepage": "https://github.com/Heretek-AI/IUMBTEMS"
29
+ },
30
+ {
31
+ "name": "research-cache",
32
+ "description": "Content-addressed SHA256 Markdown source hashing and verbatim quote verification engine.",
33
+ "author": {
34
+ "name": "Heretek AI"
35
+ },
36
+ "category": "research",
37
+ "source": "./plugins/research-cache",
38
+ "homepage": "https://github.com/Heretek-AI/IUMBTEMS"
12
39
  }
13
- }
40
+ ]
14
41
  }
@@ -1,58 +1,64 @@
1
1
  {
2
2
  "name": "epistemic-swarm",
3
- "version": "0.1.0",
3
+ "version": "0.2.2",
4
4
  "description": "High-Integrity Dialectic Research Agent Harness for Claude Code enforcing empirical evidence over parametric hallucination.",
5
- "author": "Heretek AI",
5
+ "author": {
6
+ "name": "Heretek AI",
7
+ "email": "dev@heretek.ai"
8
+ },
6
9
  "license": "Apache-2.0",
7
10
  "repository": "https://github.com/Heretek-AI/IUMBTEMS",
11
+ "homepage": "https://github.com/Heretek-AI/IUMBTEMS#readme",
12
+ "userConfig": {
13
+ "brave_api_key": {
14
+ "type": "string",
15
+ "title": "Brave Search API Key",
16
+ "description": "API key for Brave Search discovery (optional; zero-key DuckDuckGo fallback is used when unset)",
17
+ "sensitive": true,
18
+ "required": false
19
+ },
20
+ "firecrawl_api_key": {
21
+ "type": "string",
22
+ "title": "Firecrawl API Key",
23
+ "description": "API key for Firecrawl deep web extraction (optional; zero-key readability fallback is used when unset)",
24
+ "sensitive": true,
25
+ "required": false
26
+ },
27
+ "firecrawl_api_url": {
28
+ "type": "string",
29
+ "title": "Firecrawl API URL",
30
+ "description": "Endpoint for Firecrawl API or self-hosted instance",
31
+ "default": "https://api.firecrawl.dev",
32
+ "required": false
33
+ },
34
+ "searxng_url": {
35
+ "type": "string",
36
+ "title": "SearXNG URL",
37
+ "description": "Endpoint for self-hosted SearXNG metasearch instance",
38
+ "default": "http://localhost:8080",
39
+ "required": false
40
+ }
41
+ },
8
42
  "mcpServers": {
9
43
  "brave-search": {
10
- "command": "npx",
11
- "args": ["-y", "@modelcontextprotocol/server-brave-search"],
12
- "env": {
13
- "BRAVE_SEARCH_API_KEY": "${BRAVE_SEARCH_API_KEY}"
14
- }
44
+ "command": "python3",
45
+ "args": ["${CLAUDE_PLUGIN_ROOT}/config/mcp_launcher.py", "brave-search"]
15
46
  },
16
47
  "firecrawl": {
17
- "command": "npx",
18
- "args": ["-y", "firecrawl-mcp"],
19
- "env": {
20
- "FIRECRAWL_API_KEY": "${FIRECRAWL_API_KEY}",
21
- "FIRECRAWL_API_URL": "${FIRECRAWL_API_URL:-http://localhost:3002}"
22
- }
48
+ "command": "python3",
49
+ "args": ["${CLAUDE_PLUGIN_ROOT}/config/mcp_launcher.py", "firecrawl"]
23
50
  },
24
51
  "searxng": {
25
52
  "command": "python3",
26
- "args": ["${PLUGIN_DIR}/config/searxng_mcp.py"],
27
- "env": {
28
- "SEARXNG_URL": "${SEARXNG_URL:-http://localhost:8080}"
29
- }
53
+ "args": ["${CLAUDE_PLUGIN_ROOT}/config/mcp_launcher.py", "searxng"]
30
54
  }
31
55
  },
32
56
  "skills": [
33
57
  "./skills/grilling",
34
- "./skills/research-cache"
35
- ],
36
- "configuration": {
37
- "SEARXNG_URL": {
38
- "type": "string",
39
- "description": "SearXNG metasearch instance URL",
40
- "default": "http://localhost:8080"
41
- },
42
- "FIRECRAWL_API_URL": {
43
- "type": "string",
44
- "description": "Firecrawl API endpoint for JS/Markdown extraction",
45
- "default": "http://localhost:3002"
46
- },
47
- "FIRECRAWL_API_KEY": {
48
- "type": "string",
49
- "description": "Firecrawl API Key (optional for self-hosted instances)",
50
- "default": ""
51
- },
52
- "BRAVE_SEARCH_API_KEY": {
53
- "type": "string",
54
- "description": "Brave Search API Key for discovery",
55
- "default": ""
56
- }
57
- }
58
+ "./skills/research_cache",
59
+ "./skills/epistemic_search",
60
+ "./skills/swarm_config",
61
+ "./skills/code_audit",
62
+ "./skills/oss_scout"
63
+ ]
58
64
  }
package/MARKETPLACE.md ADDED
@@ -0,0 +1,93 @@
1
+ # Heretek AI Claude Code Marketplace 🏪
2
+
3
+ Official marketplace catalog for Claude Code plugins, skills, and autonomous agent harnesses developed by [Heretek AI](https://github.com/Heretek-AI).
4
+
5
+ [![Claude Code Compatible](https://img.shields.io/badge/Claude_Code-2.1+-blue.svg)](https://claude.com)
6
+ [![Marketplace Validated](https://img.shields.io/badge/Marketplace-Validated_Strict-success.svg)](https://github.com/Heretek-AI/IUMBTEMS/actions/workflows/validate-marketplace.yml)
7
+ [![npm version](https://img.shields.io/npm/v/@heretek-ai/epistemic-swarm.svg)](https://www.npmjs.com/package/@heretek-ai/epistemic-swarm)
8
+
9
+ ---
10
+
11
+ ## 🚀 Quick Start: Adding the Marketplace
12
+
13
+ To register the **`heretek-official`** marketplace in Claude Code, run:
14
+
15
+ ```bash
16
+ claude plugin marketplace add Heretek-AI/IUMBTEMS
17
+ ```
18
+
19
+ Verify that the marketplace is configured:
20
+ ```bash
21
+ claude plugin marketplace list
22
+ ```
23
+
24
+ ---
25
+
26
+ ## 📦 Available Plugins
27
+
28
+ | Plugin Name | Category | Description | Install Command |
29
+ |---|---|---|---|
30
+ | **`epistemic-swarm`** | `research` | **Flagship Swarm Harness**: Multi-agent dialectic research harness pairing Agent Alpha (Thesis) against Agent Beta (Red Team), audited by an Epistemic Auditor with verbatim empirical quote validation. | `claude plugin install epistemic-swarm@heretek-official` |
31
+ | **`socratic-grilling`** | `agents` | **Socratic Ideation**: Matt Pocock-style Socratic interrogation, premise inversion, and lateral exploration skill. | `claude plugin install socratic-grilling@heretek-official` |
32
+ | **`research-cache`** | `research` | **Source Hasher**: Content-addressed SHA256 Markdown source hashing and verbatim quote verification engine. | `claude plugin install research-cache@heretek-official` |
33
+
34
+ ---
35
+
36
+ ## 🛠️ Plugin Details & Component Breakdown
37
+
38
+ ### 1. `epistemic-swarm` (Flagship Harness)
39
+ - **Manifest**: [`.claude-plugin/plugin.json`](file:///.claude-plugin/plugin.json)
40
+ - **Components**:
41
+ - **Skills**: `skills/grilling`, `skills/research_cache`, `skills/epistemic_search`
42
+ - **Hooks**: `hooks/hooks.json` (`PreToolUse` hook intercepting ungrounded `WebSearch` and `WebFetch` to enforce verifiable SHA-256 caching)
43
+ - **Zero-Key Search**: DuckDuckGo Lite search and automated content-addressed document caching out of the box (zero API key required).
44
+ - **Safe MCP Servers & Accelerators**:
45
+ - `brave-search`: Optional Brave SERP discovery (falls back smoothly to DuckDuckGo when unconfigured).
46
+ - `firecrawl`: Optional Firecrawl JS extraction (falls back smoothly to clean readability reader when unconfigured).
47
+ - `searxng`: Optional self-hosted metasearch instance proxy.
48
+ - **System Prompts**: Base Epistemic System Override, Agent Alpha, Agent Beta, Epistemic Auditor, Orchestrator.
49
+ - **Install & Configuration**:
50
+ ```bash
51
+ claude plugin install epistemic-swarm@heretek-official
52
+ # Configure optional API keys and endpoints interactively:
53
+ claude plugin configure epistemic-swarm
54
+ # Or inside Claude Code interactive session: /plugin configure
55
+ ```
56
+
57
+ ### 2. `socratic-grilling` (Modular Skill)
58
+ - **Manifest**: [`plugins/socratic-grilling/.claude-plugin/plugin.json`](file:///plugins/socratic-grilling/.claude-plugin/plugin.json)
59
+ - **Components**:
60
+ - **Skill**: `skills/grilling` (`/grilling` slash command and interactive decision tree).
61
+ - **Install**:
62
+ ```bash
63
+ claude plugin install socratic-grilling@heretek-official
64
+ ```
65
+
66
+ ### 3. `research-cache` (Modular Tool)
67
+ - **Manifest**: [`plugins/research-cache/.claude-plugin/plugin.json`](file:///plugins/research-cache/.claude-plugin/plugin.json)
68
+ - **Components**:
69
+ - **Skill & Engine**: `skills/research-cache` (Content-addressed SHA256 raw source storage and quote validation).
70
+ - **Install**:
71
+ ```bash
72
+ claude plugin install research-cache@heretek-official
73
+ ```
74
+
75
+ ---
76
+
77
+ ## 🔍 Inspecting Installed Plugins
78
+
79
+ To view installed plugins and their active components:
80
+ ```bash
81
+ claude plugin list
82
+ claude plugin details epistemic-swarm@heretek-official
83
+ ```
84
+
85
+ To update all installed plugins to their latest versions:
86
+ ```bash
87
+ claude plugin update epistemic-swarm
88
+ ```
89
+
90
+ To uninstall:
91
+ ```bash
92
+ claude plugin uninstall epistemic-swarm
93
+ ```
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@heretek-ai/epistemic-swarm.svg)](https://www.npmjs.com/package/@heretek-ai/epistemic-swarm)
4
4
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
5
  [![CI/CD](https://github.com/Heretek-AI/IUMBTEMS/actions/workflows/publish.yml/badge.svg)](https://github.com/Heretek-AI/IUMBTEMS/actions)
6
+ [![Marketplace Validated](https://github.com/Heretek-AI/IUMBTEMS/actions/workflows/validate-marketplace.yml/badge.svg)](https://github.com/Heretek-AI/IUMBTEMS/actions)
6
7
 
7
8
  > **High-Integrity Dialectic Research Agent Harness**
8
9
  > *Universal support for Claude Code, Pi (pi.dev), and OpenCode V2.*
@@ -27,8 +28,26 @@ Modern LLMs suffer from parametric hallucination, sycophancy, and premature narr
27
28
 
28
29
  IUMBTEMS is packaged as a single universal npm package (`@heretek-ai/epistemic-swarm` with `iumbtems` binary) that runs across the three major autonomous agent platforms:
29
30
 
30
- ### 1. Claude Code
31
- Install skills and MCP servers into `~/.claude/` and `~/.claude.json`:
31
+ ### 1. Claude Code (Native Marketplace & Overlay)
32
+
33
+ #### Native Marketplace (Recommended)
34
+ Add the official Heretek AI marketplace to Claude Code:
35
+ ```bash
36
+ claude plugin marketplace add Heretek-AI/IUMBTEMS
37
+ ```
38
+ Then install either the flagship harness or modular standalone plugins:
39
+ ```bash
40
+ # Flagship dialectic research harness:
41
+ claude plugin install epistemic-swarm@heretek-official
42
+
43
+ # Or install standalone modular plugins:
44
+ claude plugin install socratic-grilling@heretek-official
45
+ claude plugin install research-cache@heretek-official
46
+ ```
47
+ See [MARKETPLACE.md](MARKETPLACE.md) for full component specifications.
48
+
49
+ #### CLI Overlay Installer
50
+ Install skills and MCP servers directly into `~/.claude/` and `~/.claude.json`:
32
51
  ```bash
33
52
  npx @heretek-ai/epistemic-swarm install
34
53
  # or from local repo:
@@ -69,6 +88,16 @@ OpenCode V2 automatically registers:
69
88
  ## ⚡ CLI Command Reference
70
89
 
71
90
  ```bash
91
+ # Inspect or update active configuration (search engine, depth, mode)
92
+ iumbtems config
93
+ iumbtems config --engine duckduckgo --depth 3 --mode audit
94
+
95
+ # Run dialectic codebase architecture & security audit
96
+ iumbtems audit "runner/ and skills/ concurrency and injection security"
97
+
98
+ # Scout open-source software, mature libraries & clean-room blueprints
99
+ iumbtems scout "Zero-dependency Raft consensus implementations in Rust"
100
+
72
101
  # Run the autonomous dialectic research swarm
73
102
  iumbtems run "Sub-millisecond ZK state updates on L1 rollups"
74
103
 
@@ -82,6 +111,14 @@ iumbtems doctor
82
111
  iumbtems test
83
112
  ```
84
113
 
114
+ ### Specialized Dialectic Skills & Slash Commands
115
+ - **`/swarm-config`**: Interactive tuning of search engines (DuckDuckGo, Brave, Firecrawl, SearXNG), iteration depth, divergence thresholds, and operating modes.
116
+ - **`/code-audit`**: Dialectic codebase review pairing a Structural Architect (thesis) with a Vulnerability Red-Teamer (antithesis) enforcing line-number proofs (`file:///path#L10-25`).
117
+ - **`/oss-scout`**: Evaluates GitHub repositories, package ecosystems (npm, crates.io, PyPI), license contamination (GPL/AGPL copyleft vs MIT/Apache), and outputs clean-room re-implementation blueprints.
118
+ - **`/grilling`**: Socratic assumption-inversion and Matt Pocock-style design tree frontier discovery.
119
+ - **`epistemic_search`**: Zero-key DuckDuckGo Lite search and content-addressed fetch with automatic SHA-256 caching.
120
+
121
+
85
122
  ---
86
123
 
87
124
  ## 🏷️ Epistemic Tagging Taxonomy
package/bin/cli.js CHANGED
@@ -25,9 +25,13 @@ Usage:
25
25
  npx @heretek-ai/epistemic-swarm <command> [options]
26
26
 
27
27
  Commands:
28
+ config [options] Inspect or modify swarm parameters (engine, depth, mode)
29
+ audit "<target>" Run dialectic codebase architectural & security audit
30
+ scout "<feature>" Scout open-source software, libraries & clean-room blueprints
28
31
  run "<objective>" Run the dialectic multi-agent research swarm
29
32
  grill Launch interactive Socratic decision tree framing
30
33
  install Install skills & MCP servers into ~/.claude/
34
+ marketplace Show Claude Code marketplace catalog & install commands
31
35
  test Run test suite for hashing, state machine & auditor
32
36
  doctor Check environment requirements (Claude Code, Pi, OpenCode)
33
37
  help Show this help message
@@ -40,9 +44,15 @@ Platform Extensions:
40
44
  Options:
41
45
  --mock-claude Run swarm with synthetic mock responses (zero API cost)
42
46
  --frontier <file> Path to settled frontier.json from Socratic grilling
47
+ --mode <mode> Operating mode (research, audit, scout, hybrid)
48
+ --engine <engine> Search engine (duckduckgo, brave, firecrawl, searxng)
49
+ --depth <n> Max dialectic iterations (1-4)
43
50
  --dir <path> Path to .research workspace directory (default: .research)
44
51
 
45
52
  Examples:
53
+ iumbtems config --engine duckduckgo --depth 3
54
+ iumbtems audit "runner/ and skills/ concurrency & security"
55
+ iumbtems scout "Zero-dependency Raft consensus in Rust"
46
56
  iumbtems run "Verify sub-millisecond ZK prover latency"
47
57
  iumbtems grill --objective "Rollup architecture trade-offs"
48
58
  iumbtems doctor
@@ -75,6 +85,31 @@ function runBash(scriptRelPath, extraArgs = []) {
75
85
  }
76
86
 
77
87
  switch (command) {
88
+ case 'config': {
89
+ runPython('skills/swarm_config/configure.py', args.slice(1));
90
+ break;
91
+ }
92
+
93
+ case 'audit': {
94
+ const targetObj = args[1] && !args[1].startsWith('--') ? args[1] : 'Full codebase architectural and security audit';
95
+ const restArgs = args[1] && !args[1].startsWith('--') ? args.slice(2) : args.slice(1);
96
+ const forwardArgs = ['--mode', 'audit', '--objective', targetObj, ...restArgs];
97
+ runPython('runner/research_swarm.py', forwardArgs);
98
+ break;
99
+ }
100
+
101
+ case 'scout': {
102
+ const objective = args[1];
103
+ if (!objective || objective.startsWith('--')) {
104
+ console.error('Error: Please provide a feature or library to scout.');
105
+ console.error('Example: npx @heretek-ai/epistemic-swarm scout "Zero-dependency Raft in Rust"');
106
+ process.exit(1);
107
+ }
108
+ const forwardArgs = ['--mode', 'scout', '--objective', objective, ...args.slice(2)];
109
+ runPython('runner/research_swarm.py', forwardArgs);
110
+ break;
111
+ }
112
+
78
113
  case 'run': {
79
114
  const objective = args[1];
80
115
  if (!objective || objective.startsWith('--')) {
@@ -97,6 +132,29 @@ switch (command) {
97
132
  break;
98
133
  }
99
134
 
135
+ case 'marketplace': {
136
+ const mktPath = path.join(PKG_ROOT, '.claude-plugin', 'marketplace.json');
137
+ if (!fs.existsSync(mktPath)) {
138
+ console.error('Marketplace manifest not found.');
139
+ process.exit(1);
140
+ }
141
+ const mkt = JSON.parse(fs.readFileSync(mktPath, 'utf8'));
142
+ console.log(`\n🏪 CLAUDE CODE MARKETPLACE: ${mkt.name.toUpperCase()}`);
143
+ console.log(`================================================`);
144
+ console.log(`Owner: ${mkt.owner ? mkt.owner.name : 'Unknown'} <${mkt.owner ? mkt.owner.email : ''}>`);
145
+ console.log(`Description: ${mkt.description}\n`);
146
+ console.log(`🚀 Add this marketplace to Claude Code:`);
147
+ console.log(` claude plugin marketplace add Heretek-AI/IUMBTEMS\n`);
148
+ console.log(`📦 Available Plugins in Marketplace:`);
149
+ (mkt.plugins || []).forEach((p, idx) => {
150
+ console.log(` ${idx + 1}. ${p.name} [${p.category || 'plugin'}]`);
151
+ console.log(` Description: ${p.description}`);
152
+ console.log(` Install: claude plugin install ${p.name}@${mkt.name}`);
153
+ console.log(` Configure: claude plugin configure ${p.name}@${mkt.name}\n`);
154
+ });
155
+ break;
156
+ }
157
+
100
158
  case 'test': {
101
159
  runPython('-m', ['unittest', 'discover', '-s', 'runner/tests']);
102
160
  break;
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Intelligent MCP Server Launcher & Epistemic Fallback Proxy for IUMBTEMS.
4
+ Safely detects API keys and endpoints:
5
+ - If keys are present (via env or userConfig): launches the official MCP server.
6
+ - If keys are absent: smoothly provides a zero-key JSON-RPC fallback MCP server
7
+ backed by DuckDuckGo Lite search and content-addressed SHA256 caching.
8
+ Prevents startup crashes and missing environment variable errors in Claude Code.
9
+ """
10
+
11
+ import sys
12
+ import os
13
+ import json
14
+ import subprocess
15
+ import shutil
16
+ from typing import Dict, Any, List
17
+
18
+ # Add parent dir to path for imports
19
+ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
20
+ PROJECT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
21
+ if PROJECT_ROOT not in sys.path:
22
+ sys.path.insert(0, PROJECT_ROOT)
23
+
24
+ def get_config_val(key: str, default: str = "") -> str:
25
+ """Retrieve config from env, userConfig, or defaults."""
26
+ env_val = os.environ.get(key)
27
+ if env_val:
28
+ return env_val
29
+ # Also check user_config format
30
+ user_cfg_val = os.environ.get(f"CLAUDE_PLUGIN_OPTION_{key.upper()}")
31
+ if user_cfg_val:
32
+ return user_cfg_val
33
+ return default
34
+
35
+ def run_zero_key_mcp_server(service: str):
36
+ """Run lightweight JSON-RPC MCP server handling search and fetch without API keys."""
37
+ from skills.epistemic_search.scripts.search import search_duckduckgo
38
+ from skills.epistemic_search.scripts.fetch import fetch_and_cache
39
+
40
+ def send_response(response: Dict[str, Any]):
41
+ out = json.dumps(response)
42
+ sys.stdout.write(f"Content-Length: {len(out)}\r\n\r\n{out}")
43
+ sys.stdout.flush()
44
+
45
+ def send_json(response: Dict[str, Any]):
46
+ # Direct newline JSON-RPC for stdio transports
47
+ sys.stdout.write(json.dumps(response) + "\n")
48
+ sys.stdout.flush()
49
+
50
+ while True:
51
+ try:
52
+ line = sys.stdin.readline()
53
+ if not line:
54
+ break
55
+ line = line.strip()
56
+ if not line:
57
+ continue
58
+
59
+ # Check if line is Content-Length header or raw JSON
60
+ if line.startswith("Content-Length:"):
61
+ length = int(line.split(":")[1].strip())
62
+ # Read blank line
63
+ sys.stdin.readline()
64
+ body = sys.stdin.read(length)
65
+ req = json.loads(body)
66
+ use_headers = True
67
+ else:
68
+ req = json.loads(line)
69
+ use_headers = False
70
+
71
+ req_id = req.get("id")
72
+ method = req.get("method")
73
+ params = req.get("params", {})
74
+
75
+ if method == "initialize":
76
+ res = {
77
+ "jsonrpc": "2.0",
78
+ "id": req_id,
79
+ "result": {
80
+ "protocolVersion": "2024-11-05",
81
+ "serverInfo": {
82
+ "name": f"epistemic-{service}-fallback",
83
+ "version": "0.2.1"
84
+ },
85
+ "capabilities": {
86
+ "tools": {}
87
+ }
88
+ }
89
+ }
90
+ elif method == "tools/list":
91
+ if service == "brave-search":
92
+ tools = [
93
+ {
94
+ "name": "brave_web_search",
95
+ "description": "Web search with DuckDuckGo fallback (zero API key required). Returns verifiable search results with titles, URLs, and snippets.",
96
+ "inputSchema": {
97
+ "type": "object",
98
+ "properties": {
99
+ "query": {"type": "string", "description": "The search query terms"},
100
+ "count": {"type": "number", "description": "Number of results (1-20)", "default": 10}
101
+ },
102
+ "required": ["query"]
103
+ }
104
+ }
105
+ ]
106
+ elif service == "firecrawl":
107
+ tools = [
108
+ {
109
+ "name": "firecrawl_scrape",
110
+ "description": "Scrape and extract clean markdown with automatic content-addressed SHA-256 caching into .research/sources/.",
111
+ "inputSchema": {
112
+ "type": "object",
113
+ "properties": {
114
+ "url": {"type": "string", "description": "URL to scrape and cache"}
115
+ },
116
+ "required": ["url"]
117
+ }
118
+ }
119
+ ]
120
+ else:
121
+ tools = []
122
+
123
+ res = {
124
+ "jsonrpc": "2.0",
125
+ "id": req_id,
126
+ "result": {"tools": tools}
127
+ }
128
+ elif method == "tools/call":
129
+ tool_name = params.get("name")
130
+ args = params.get("arguments", {})
131
+
132
+ if tool_name in ("brave_web_search", "search"):
133
+ q = args.get("query", "")
134
+ count = args.get("count", 10)
135
+ results = search_duckduckgo(query=q, max_results=count)
136
+ text_out = json.dumps(results, indent=2)
137
+ res = {
138
+ "jsonrpc": "2.0",
139
+ "id": req_id,
140
+ "result": {
141
+ "content": [{"type": "text", "text": text_out}]
142
+ }
143
+ }
144
+ elif tool_name in ("firecrawl_scrape", "scrape", "fetch"):
145
+ target_url = args.get("url", "")
146
+ content = fetch_and_cache(url=target_url)
147
+ res = {
148
+ "jsonrpc": "2.0",
149
+ "id": req_id,
150
+ "result": {
151
+ "content": [{"type": "text", "text": content}]
152
+ }
153
+ }
154
+ else:
155
+ res = {
156
+ "jsonrpc": "2.0",
157
+ "id": req_id,
158
+ "error": {"code": -32601, "message": f"Tool {tool_name} not found"}
159
+ }
160
+ elif method == "notifications/initialized":
161
+ continue
162
+ else:
163
+ res = {
164
+ "jsonrpc": "2.0",
165
+ "id": req_id,
166
+ "error": {"code": -32601, "message": f"Method {method} not handled"}
167
+ }
168
+
169
+ if use_headers:
170
+ send_response(res)
171
+ else:
172
+ send_json(res)
173
+
174
+ except Exception as e:
175
+ sys.stderr.write(f"[mcp-launcher] Error handling request: {e}\n")
176
+ break
177
+
178
+ def main():
179
+ service = sys.argv[1] if len(sys.argv) > 1 else "brave-search"
180
+ npx_bin = shutil.which("npx")
181
+
182
+ if service == "brave-search":
183
+ api_key = get_config_val("BRAVE_SEARCH_API_KEY")
184
+ if api_key and npx_bin:
185
+ os.environ["BRAVE_SEARCH_API_KEY"] = api_key
186
+ os.execvp(npx_bin, [npx_bin, "-y", "@modelcontextprotocol/server-brave-search"])
187
+ else:
188
+ # Fall back to zero-key search proxy
189
+ run_zero_key_mcp_server("brave-search")
190
+
191
+ elif service == "firecrawl":
192
+ api_key = get_config_val("FIRECRAWL_API_KEY")
193
+ api_url = get_config_val("FIRECRAWL_API_URL", "https://api.firecrawl.dev")
194
+ if api_key and npx_bin:
195
+ os.environ["FIRECRAWL_API_KEY"] = api_key
196
+ os.environ["FIRECRAWL_API_URL"] = api_url
197
+ os.execvp(npx_bin, [npx_bin, "-y", "firecrawl-mcp"])
198
+ else:
199
+ # Fall back to zero-key readability fetcher + SHA-256 hasher
200
+ run_zero_key_mcp_server("firecrawl")
201
+
202
+ elif service == "searxng":
203
+ searxng_url = get_config_val("SEARXNG_URL", "http://localhost:8080")
204
+ searxng_script = os.path.join(SCRIPT_DIR, "searxng_mcp.py")
205
+ if os.path.exists(searxng_script):
206
+ os.environ["SEARXNG_URL"] = searxng_url
207
+ os.execvp("python3", ["python3", searxng_script])
208
+ else:
209
+ run_zero_key_mcp_server("searxng")
210
+ else:
211
+ sys.stderr.write(f"Unknown service: {service}\n")
212
+ sys.exit(1)
213
+
214
+ if __name__ == "__main__":
215
+ main()
@@ -0,0 +1,24 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "WebSearch",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"WebSearch intercepted by epistemic-swarm to enforce verified citation integrity. Use epistemic search (python3 ${CLAUDE_PLUGIN_ROOT}/skills/epistemic_search/scripts/search.py \\\"<query>\\\") instead.\"}}'"
10
+ }
11
+ ]
12
+ },
13
+ {
14
+ "matcher": "WebFetch",
15
+ "hooks": [
16
+ {
17
+ "type": "command",
18
+ "command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"WebFetch intercepted by epistemic-swarm to enforce content-addressed caching. Use epistemic fetch (python3 ${CLAUDE_PLUGIN_ROOT}/skills/epistemic_search/scripts/fetch.py \\\"<url>\\\") which automatically stores documents in .research/sources/<sha256>.md for mathematical auditability.\"}}'"
19
+ }
20
+ ]
21
+ }
22
+ ]
23
+ }
24
+ }