@heretek-ai/epistemic-swarm 0.1.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.
- package/.claude-plugin/marketplace.json +36 -9
- package/.claude-plugin/plugin.json +47 -41
- package/MARKETPLACE.md +93 -0
- package/README.md +117 -74
- package/bin/cli.js +73 -8
- package/config/mcp_launcher.py +215 -0
- package/config/opencode-snippet.json +48 -0
- package/extensions/pi/index.js +90 -0
- package/hooks/hooks.json +24 -0
- package/package.json +52 -5
- package/plugins/opencode/index.js +149 -0
- package/plugins/research-cache/.claude-plugin/plugin.json +15 -0
- package/plugins/socratic-grilling/.claude-plugin/plugin.json +15 -0
- package/plugins/socratic-grilling/skills/grilling/SKILL.md +48 -0
- package/plugins/socratic-grilling/skills/grilling/__init__.py +0 -0
- package/plugins/socratic-grilling/skills/grilling/socratic_tree.py +148 -0
- package/prompts/agent_code_auditor.md +88 -0
- package/prompts/agent_oss_scout.md +78 -0
- package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
- package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
- package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
- package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
- package/runner/research_swarm.py +230 -81
- package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
- package/runner/tests/test_swarm.py +66 -0
- package/skills/code_audit/SKILL.md +45 -0
- package/skills/epistemic_search/SKILL.md +35 -0
- package/skills/epistemic_search/__init__.py +1 -0
- package/skills/epistemic_search/scripts/fetch.py +157 -0
- package/skills/epistemic_search/scripts/search.py +162 -0
- package/skills/oss_scout/SKILL.md +49 -0
- package/skills/research_cache/SKILL.md +36 -0
- package/skills/research_cache/__init__.py +0 -0
- package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
- package/skills/research_cache/hasher.py +195 -0
- package/skills/swarm_config/SKILL.md +72 -0
- package/skills/swarm_config/__init__.py +4 -0
- package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
- package/skills/swarm_config/configure.py +167 -0
- package/runner/__pycache__/__init__.cpython-314.pyc +0 -0
- package/runner/__pycache__/auditor_engine.cpython-314.pyc +0 -0
- package/runner/__pycache__/research_swarm.cpython-314.pyc +0 -0
- package/runner/__pycache__/state_machine.cpython-314.pyc +0 -0
- package/runner/tests/__pycache__/test_swarm.cpython-314.pyc +0 -0
- package/skills/research-cache/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/research-cache/__pycache__/hasher.cpython-314.pyc +0 -0
- /package/{skills/research-cache → plugins/research-cache/skills/research_cache}/SKILL.md +0 -0
- /package/{skills/research-cache → plugins/research-cache/skills/research_cache}/__init__.py +0 -0
- /package/{skills/research-cache → plugins/research-cache/skills/research_cache}/hasher.py +0 -0
|
@@ -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,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://opencode.ai/config.json",
|
|
3
|
+
"plugin": [
|
|
4
|
+
"@heretek-ai/epistemic-swarm"
|
|
5
|
+
],
|
|
6
|
+
"agent": {
|
|
7
|
+
"alpha-thesis": {
|
|
8
|
+
"description": "IUMBTEMS Proponent Agent: Gathers corroborating primary sources, benchmark results, and empirical proofs.",
|
|
9
|
+
"tools": {
|
|
10
|
+
"bash": true,
|
|
11
|
+
"read": true,
|
|
12
|
+
"write": true,
|
|
13
|
+
"grep": true,
|
|
14
|
+
"glob": true,
|
|
15
|
+
"task": true,
|
|
16
|
+
"iumbtems_verify_quote": true
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"beta-redteam": {
|
|
20
|
+
"description": "IUMBTEMS Adversary Agent: Active falsification, red-teaming, hunting for counter-benchmarks, and edge-case failure modes.",
|
|
21
|
+
"tools": {
|
|
22
|
+
"bash": true,
|
|
23
|
+
"read": true,
|
|
24
|
+
"write": true,
|
|
25
|
+
"grep": true,
|
|
26
|
+
"glob": true,
|
|
27
|
+
"task": true,
|
|
28
|
+
"iumbtems_verify_quote": true
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"epistemic-auditor": {
|
|
32
|
+
"description": "IUMBTEMS Synthesizer & Auditor: Verifies verbatim source quotes, downgrades unverified claims, and calculates divergence.",
|
|
33
|
+
"tools": {
|
|
34
|
+
"read": true,
|
|
35
|
+
"write": true,
|
|
36
|
+
"grep": true,
|
|
37
|
+
"glob": true,
|
|
38
|
+
"iumbtems_verify_quote": true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"skills": {
|
|
43
|
+
"paths": [
|
|
44
|
+
"./skills/grilling",
|
|
45
|
+
"./skills/research-cache"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IUMBTEMS: I Use My Brain To Express My Self
|
|
3
|
+
* Native Extension for Pi (pi.dev)
|
|
4
|
+
*
|
|
5
|
+
* Exposes /grill and /swarm slash commands and epistemic verification tools in Pi.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawnSync } from 'child_process';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
const PKG_ROOT = path.resolve(__dirname, '../..');
|
|
15
|
+
|
|
16
|
+
export default function initPiExtension(pi) {
|
|
17
|
+
// Check if Pi extension API is available
|
|
18
|
+
if (!pi) return;
|
|
19
|
+
|
|
20
|
+
// 1. Register /swarm slash command
|
|
21
|
+
if (typeof pi.registerCommand === 'function') {
|
|
22
|
+
pi.registerCommand('swarm', {
|
|
23
|
+
description: 'Run IUMBTEMS dialectic research swarm on an objective',
|
|
24
|
+
usage: '/swarm <objective>',
|
|
25
|
+
handler: async (args, ctx) => {
|
|
26
|
+
const objective = args.trim();
|
|
27
|
+
if (!objective) {
|
|
28
|
+
ctx.output?.('⚠️ Please provide a research objective. Example: /swarm "ZK prover latency bounds"');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
ctx.output?.(`🌟 [IUMBTEMS] Dispatching Dialectic Swarm: "${objective}"...`);
|
|
33
|
+
const runnerPath = path.join(PKG_ROOT, 'runner/research_swarm.py');
|
|
34
|
+
const res = spawnSync('python3', [runnerPath, '--objective', objective], {
|
|
35
|
+
encoding: 'utf-8',
|
|
36
|
+
cwd: ctx.cwd || process.cwd(),
|
|
37
|
+
env: { ...process.env, PYTHONPATH: PKG_ROOT }
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (res.status === 0) {
|
|
41
|
+
ctx.output?.(res.stdout);
|
|
42
|
+
ctx.output?.('\n✅ Research complete! Summary written to .research/final_synthesis.md');
|
|
43
|
+
} else {
|
|
44
|
+
ctx.output?.(`❌ Swarm failed:\n${res.stderr || res.stdout}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// 2. Register /grill slash command
|
|
50
|
+
pi.registerCommand('grill', {
|
|
51
|
+
description: 'Launch Socratic grilling and decision tree frontier exploration',
|
|
52
|
+
usage: '/grill [--objective <text>]',
|
|
53
|
+
handler: async (args, ctx) => {
|
|
54
|
+
ctx.output?.('🧠 [IUMBTEMS] Launching Socratic Grilling decision tree...');
|
|
55
|
+
const treePath = path.join(PKG_ROOT, 'skills/grilling/socratic_tree.py');
|
|
56
|
+
const forwardArgs = args.trim() ? ['--objective', args.trim()] : ['--show-frontier'];
|
|
57
|
+
const res = spawnSync('python3', [treePath, ...forwardArgs], {
|
|
58
|
+
encoding: 'utf-8',
|
|
59
|
+
cwd: ctx.cwd || process.cwd()
|
|
60
|
+
});
|
|
61
|
+
ctx.output?.(res.stdout || res.stderr);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 3. Register tool for epistemic quote verification
|
|
67
|
+
if (typeof pi.registerTool === 'function') {
|
|
68
|
+
pi.registerTool({
|
|
69
|
+
name: 'iumbtems_verify_quote',
|
|
70
|
+
description: 'Verify that an empirical claim quote matches verbatim text in the source cache',
|
|
71
|
+
parameters: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
hash: { type: 'string', description: 'SHA-256 hash of cached source' },
|
|
75
|
+
quote: { type: 'string', description: 'Verbatim quote string to verify' }
|
|
76
|
+
},
|
|
77
|
+
required: ['hash', 'quote']
|
|
78
|
+
},
|
|
79
|
+
execute: async ({ hash, quote }) => {
|
|
80
|
+
const hasherPath = path.join(PKG_ROOT, 'skills/research-cache/hasher.py');
|
|
81
|
+
const res = spawnSync('python3', [hasherPath, 'verify', '--hash', hash, '--quote', quote], {
|
|
82
|
+
encoding: 'utf-8'
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: 'text', text: res.stdout || res.stderr }]
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
package/hooks/hooks.json
ADDED
|
@@ -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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heretek-ai/epistemic-swarm",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "IUMBTEMS: I Use My Brain To Express My Self — High-Integrity Dialectic Research Agent Harness for Claude Code, Pi (pi.dev), and OpenCode V2",
|
|
5
5
|
"main": "bin/cli.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"iumbtems": "bin/cli.js",
|
|
8
|
+
"epistemic-swarm": "bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./bin/cli.js",
|
|
12
|
+
"./opencode": "./plugins/opencode/index.js",
|
|
13
|
+
"./server": "./plugins/opencode/index.js",
|
|
14
|
+
"./pi": "./extensions/pi/index.js"
|
|
9
15
|
},
|
|
10
16
|
"publishConfig": {
|
|
11
17
|
"access": "public"
|
|
@@ -19,26 +25,66 @@
|
|
|
19
25
|
},
|
|
20
26
|
"homepage": "https://github.com/Heretek-AI/IUMBTEMS#readme",
|
|
21
27
|
"keywords": [
|
|
28
|
+
"iumbtems",
|
|
29
|
+
"i-use-my-brain-to-express-my-self",
|
|
30
|
+
"pi-package",
|
|
31
|
+
"opencode",
|
|
32
|
+
"opencode-plugin",
|
|
22
33
|
"claude-code",
|
|
23
34
|
"ai-agents",
|
|
35
|
+
"autonomous-agents",
|
|
36
|
+
"multi-agent-systems",
|
|
24
37
|
"dialectic-swarm",
|
|
38
|
+
"dialectic",
|
|
25
39
|
"epistemic-integrity",
|
|
26
40
|
"research-harness",
|
|
41
|
+
"research-agent",
|
|
27
42
|
"mcp",
|
|
43
|
+
"model-context-protocol",
|
|
44
|
+
"mcp-servers",
|
|
28
45
|
"deep-research",
|
|
29
|
-
"socratic-grilling"
|
|
46
|
+
"socratic-grilling",
|
|
47
|
+
"socratic-questioning",
|
|
48
|
+
"fact-checking",
|
|
49
|
+
"red-teaming",
|
|
50
|
+
"citation-validation",
|
|
51
|
+
"hallucination-prevention",
|
|
52
|
+
"swarm-intelligence",
|
|
53
|
+
"code-audit",
|
|
54
|
+
"oss-scout",
|
|
55
|
+
"clean-room-engineering"
|
|
30
56
|
],
|
|
57
|
+
"pi": {
|
|
58
|
+
"extensions": [
|
|
59
|
+
"./extensions/pi/index.js"
|
|
60
|
+
],
|
|
61
|
+
"skills": [
|
|
62
|
+
"./skills/grilling",
|
|
63
|
+
"./skills/research_cache",
|
|
64
|
+
"./skills/epistemic_search",
|
|
65
|
+
"./skills/swarm_config",
|
|
66
|
+
"./skills/code_audit",
|
|
67
|
+
"./skills/oss_scout"
|
|
68
|
+
],
|
|
69
|
+
"prompts": [
|
|
70
|
+
"./prompts/*.md"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
31
73
|
"author": "Heretek AI",
|
|
32
74
|
"license": "Apache-2.0",
|
|
33
75
|
"files": [
|
|
34
76
|
"bin",
|
|
35
77
|
"prompts",
|
|
36
78
|
"skills",
|
|
79
|
+
"hooks",
|
|
37
80
|
"config",
|
|
38
81
|
"runner",
|
|
82
|
+
"extensions",
|
|
83
|
+
"plugins",
|
|
39
84
|
".claude-plugin",
|
|
40
85
|
"install.sh",
|
|
41
86
|
"README.md",
|
|
87
|
+
"MARKETPLACE.md",
|
|
42
88
|
"LICENSE"
|
|
43
89
|
],
|
|
44
90
|
"engines": {
|
|
@@ -46,6 +92,7 @@
|
|
|
46
92
|
},
|
|
47
93
|
"scripts": {
|
|
48
94
|
"test": "python3 -m unittest discover -s runner/tests",
|
|
95
|
+
"validate:claude": "claude plugin validate --strict .claude-plugin/marketplace.json && claude plugin validate --strict .",
|
|
49
96
|
"prepack": "python3 -m unittest discover -s runner/tests",
|
|
50
97
|
"install-local": "bash install.sh"
|
|
51
98
|
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IUMBTEMS: I Use My Brain To Express My Self
|
|
3
|
+
* Native Plugin for OpenCode V2 (opencode.ai)
|
|
4
|
+
*
|
|
5
|
+
* Exposes dialectic swarm research tools, Socratic decision frontier calculation,
|
|
6
|
+
* and content-addressed quote verification directly into OpenCode V2 agents.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { spawnSync } from 'child_process';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
15
|
+
const PKG_ROOT = path.resolve(__dirname, '../..');
|
|
16
|
+
|
|
17
|
+
export function createOpenCodePlugin(context = {}) {
|
|
18
|
+
return {
|
|
19
|
+
id: "heretek.iumbtems.epistemic-swarm",
|
|
20
|
+
name: "IUMBTEMS Epistemic Swarm",
|
|
21
|
+
version: "0.1.0",
|
|
22
|
+
description: "I Use My Brain To Express My Self: Dialectic research swarm enforcing empirical verification",
|
|
23
|
+
|
|
24
|
+
server: (toolContext) => [
|
|
25
|
+
{
|
|
26
|
+
name: "iumbtems_swarm_research",
|
|
27
|
+
description: "Execute an autonomous dialectic research swarm on an objective using Agent Alpha (Thesis) and Agent Beta (Red Team).",
|
|
28
|
+
input: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
objective: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "The research question or hypothesis to investigate"
|
|
34
|
+
},
|
|
35
|
+
mock_mode: {
|
|
36
|
+
type: "boolean",
|
|
37
|
+
description: "Run in mock/dry-run mode without external API charges",
|
|
38
|
+
default: false
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
required: ["objective"]
|
|
42
|
+
},
|
|
43
|
+
options: { codemode: false },
|
|
44
|
+
execute: async (args) => {
|
|
45
|
+
const runnerPath = path.join(PKG_ROOT, "runner/research_swarm.py");
|
|
46
|
+
const cmdArgs = [runnerPath, "--objective", args.objective];
|
|
47
|
+
if (args.mock_mode) {
|
|
48
|
+
cmdArgs.push("--mock-claude");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const res = spawnSync("python3", cmdArgs, {
|
|
52
|
+
encoding: "utf-8",
|
|
53
|
+
cwd: toolContext?.cwd || process.cwd(),
|
|
54
|
+
env: { ...process.env, PYTHONPATH: PKG_ROOT }
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
content: res.stdout || res.stderr,
|
|
59
|
+
status: res.status === 0 ? "success" : "error"
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
name: "iumbtems_verify_quote",
|
|
66
|
+
description: "Cryptographically verify whether a cited quote matches verbatim text inside the content-addressed source cache.",
|
|
67
|
+
input: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
hash: {
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "SHA-256 hash or prefix of the cached source"
|
|
73
|
+
},
|
|
74
|
+
quote: {
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "The verbatim excerpt to verify"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
required: ["hash", "quote"]
|
|
80
|
+
},
|
|
81
|
+
options: { codemode: false },
|
|
82
|
+
execute: async (args) => {
|
|
83
|
+
const hasherPath = path.join(PKG_ROOT, "skills/research-cache/hasher.py");
|
|
84
|
+
const res = spawnSync("python3", [hasherPath, "verify", "--hash", args.hash, "--quote", args.quote], {
|
|
85
|
+
encoding: "utf-8",
|
|
86
|
+
cwd: toolContext?.cwd || process.cwd()
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
content: res.stdout || res.stderr,
|
|
91
|
+
status: res.status === 0 ? "verified" : "failed"
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
{
|
|
97
|
+
name: "iumbtems_socratic_frontier",
|
|
98
|
+
description: "Inspect or advance the Socratic grilling decision frontier for research framing.",
|
|
99
|
+
input: {
|
|
100
|
+
type: "object",
|
|
101
|
+
properties: {
|
|
102
|
+
objective: {
|
|
103
|
+
type: "string",
|
|
104
|
+
description: "Research objective to inspect"
|
|
105
|
+
},
|
|
106
|
+
settle_node: {
|
|
107
|
+
type: "string",
|
|
108
|
+
description: "Optional node ID to settle with an answer"
|
|
109
|
+
},
|
|
110
|
+
settle_answer: {
|
|
111
|
+
type: "string",
|
|
112
|
+
description: "Answer for the settled node"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
options: { codemode: false },
|
|
117
|
+
execute: async (args) => {
|
|
118
|
+
const treePath = path.join(PKG_ROOT, "skills/grilling/socratic_tree.py");
|
|
119
|
+
const cmdArgs = [treePath];
|
|
120
|
+
|
|
121
|
+
if (args.settle_node && args.settle_answer) {
|
|
122
|
+
cmdArgs.push("--settle", args.settle_node, args.settle_answer);
|
|
123
|
+
} else if (args.objective) {
|
|
124
|
+
cmdArgs.push("--objective", args.objective, "--show-frontier");
|
|
125
|
+
} else {
|
|
126
|
+
cmdArgs.push("--show-frontier");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const res = spawnSync("python3", cmdArgs, {
|
|
130
|
+
encoding: "utf-8",
|
|
131
|
+
cwd: toolContext?.cwd || process.cwd()
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
content: res.stdout || res.stderr
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
|
|
141
|
+
setup: async (appContext) => {
|
|
142
|
+
// OpenCode V2 lifecycle hook
|
|
143
|
+
return { initialized: true, platform: "opencode-v2" };
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const defaultPlugin = createOpenCodePlugin();
|
|
149
|
+
export default defaultPlugin;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "research-cache",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Content-addressed SHA256 Markdown source hashing and verbatim quote verification engine.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Heretek AI",
|
|
7
|
+
"email": "dev@heretek.ai"
|
|
8
|
+
},
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"repository": "https://github.com/Heretek-AI/IUMBTEMS",
|
|
11
|
+
"homepage": "https://github.com/Heretek-AI/IUMBTEMS#readme",
|
|
12
|
+
"skills": [
|
|
13
|
+
"./skills/research_cache"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "socratic-grilling",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Matt Pocock-style Socratic interrogation, premise inversion, and lateral exploration skill for Claude Code.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Heretek AI",
|
|
7
|
+
"email": "dev@heretek.ai"
|
|
8
|
+
},
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"repository": "https://github.com/Heretek-AI/IUMBTEMS",
|
|
11
|
+
"homepage": "https://github.com/Heretek-AI/IUMBTEMS#readme",
|
|
12
|
+
"skills": [
|
|
13
|
+
"./skills/grilling"
|
|
14
|
+
]
|
|
15
|
+
}
|