From 0d4ae633002852a2d4821f9a8ad821d119b2972c Mon Sep 17 00:00:00 2001 From: shivamuppal2318 <147269863+shivamuppal2318@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:13:08 +0530 Subject: [PATCH 1/2] feat(config): implement capability keywords for intelligent query routing Introduce capability keywords in meshmind.yaml defaults to enable keyword-based routing of queries to specialist nodes. Updates span config schema, orchestrator logic, and SDK integration to support passing and applying these keywords in routing plans. Added demo plugins 'demo_documentation' and 'demo_research' with corresponding specialist nodes in sample configuration. Enhanced build setup with metadata, publishing files, and package data inclusion. Fixed CLI module typo and expanded test coverage for new bundled plugins published it over the pypy package --- .tmp/manualdir/foo.json | 1 + .tmp/sitecustomize.py | 8 ++ MANIFEST.in | 15 +++ PUBLISHING.md | 36 +++++ README.md | 4 +- docs/plugins.md | 4 +- meshmind/cli/__init__.py | 1 + meshmind/cli/__inti__.py | 0 .../demo_documentation/plugin.yaml | 13 ++ .../prompts/system_prompt.txt | 1 + .../plugin_stubs/demo_research/plugin.yaml | 13 ++ .../demo_research/prompts/system_prompt.txt | 1 + meshmind/config/schema.py | 1 + meshmind/core/node.py | 1 + meshmind/core/orchestrator.py | 4 +- meshmind/sdk/mesh.py | 7 + my-project/.meshmind/repl_history | 68 ++++++++++ my-project/meshmind.yaml | 72 ++++++++-- pyproject.toml | 125 ++++++++++-------- shivam/data/knowledge.json | 7 + shivam/meshmind.yaml | 58 ++++++++ tests/test_plugin_init_ux.py | 5 + 22 files changed, 374 insertions(+), 71 deletions(-) create mode 100644 .tmp/manualdir/foo.json create mode 100644 .tmp/sitecustomize.py create mode 100644 MANIFEST.in create mode 100644 PUBLISHING.md create mode 100644 meshmind/cli/__init__.py delete mode 100644 meshmind/cli/__inti__.py create mode 100644 meshmind/cli/plugin_stubs/demo_documentation/plugin.yaml create mode 100644 meshmind/cli/plugin_stubs/demo_documentation/prompts/system_prompt.txt create mode 100644 meshmind/cli/plugin_stubs/demo_research/plugin.yaml create mode 100644 meshmind/cli/plugin_stubs/demo_research/prompts/system_prompt.txt create mode 100644 my-project/.meshmind/repl_history create mode 100644 shivam/data/knowledge.json create mode 100644 shivam/meshmind.yaml diff --git a/.tmp/manualdir/foo.json b/.tmp/manualdir/foo.json new file mode 100644 index 0000000..c1b0730 --- /dev/null +++ b/.tmp/manualdir/foo.json @@ -0,0 +1 @@ +x \ No newline at end of file diff --git a/.tmp/sitecustomize.py b/.tmp/sitecustomize.py new file mode 100644 index 0000000..07cb26a --- /dev/null +++ b/.tmp/sitecustomize.py @@ -0,0 +1,8 @@ +import tempfile + +_real_mkdir = tempfile._os.mkdir + +def _mkdir(path, mode=0o777): + return _real_mkdir(path, 0o777) + +tempfile._os.mkdir = _mkdir diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..955f2b6 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,15 @@ +include README.md +include LICENSE +include CHANGELOG.md +include CONTRIBUTING.md +include requirements.txt + +recursive-include meshmind/knowledge *.json +recursive-include meshmind/ui/template *.html +recursive-include meshmind/ui/static * +recursive-include meshmind/cli/templates *.tmpl +recursive-include meshmind/cli/presets *.yaml +recursive-include meshmind/cli/plugin_stubs *.yaml *.txt *.md + +prune meshmind.egg-info +global-exclude __pycache__ *.py[cod] diff --git a/PUBLISHING.md b/PUBLISHING.md new file mode 100644 index 0000000..7b1caf9 --- /dev/null +++ b/PUBLISHING.md @@ -0,0 +1,36 @@ +# Publishing to PyPI + +## 1) Prep + +- Make sure `pyproject.toml` has the right `project.version`. +- Update `CHANGELOG.md` (and optionally docs release notes). +- Tag the release (recommended): `git tag vX.Y.Z` + +## 2) Build + +```bash +python -m pip install -U build twine +python -m build +python -m twine check dist/* +``` + +## 3) Upload + +TestPyPI (recommended first): + +```bash +python -m twine upload -r testpypi dist/* +``` + +PyPI: + +```bash +python -m twine upload dist/* +``` + +## 4) Verify install + +```bash +python -m pip install -U meshmind +meshmind --help +``` diff --git a/README.md b/README.md index 9cc6294..9aa68a2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -
+
# MeshMind @@ -28,7 +28,7 @@ This is not distributed inference for a single giant model. MeshMind is built ar **Install (released package):** Python **3.11+** and [Ollama](https://ollama.com). Stable installs: ```bash -pip install meshmind +pip install -U meshmind ``` **Install (from source, contributors):** from the repo root: diff --git a/docs/plugins.md b/docs/plugins.md index 7e7291d..621c6ae 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -52,8 +52,8 @@ When `meshmind.yaml` sets `plugin: ""` on a node: ## Bundled demos -The repo ships stub plugins `demo_review` and `demo_security` under `meshmind/cli/plugin_stubs/`. -`meshmind init --preset code` can copy them into your plugin directory (default unless `--skip-bundled-plugins`). +The repo ships stub plugins `demo_review`, `demo_security`, `demo_documentation`, and `demo_research` under `meshmind/cli/plugin_stubs/`. +`meshmind init --preset code` can copy `demo_review` and `demo_security` into your plugin directory (default unless `--skip-bundled-plugins`). If you skipped that step or moved machines, run `meshmind plugin sync -c meshmind.yaml` before `meshmind up`. ## meshmind.yaml diff --git a/meshmind/cli/__init__.py b/meshmind/cli/__init__.py new file mode 100644 index 0000000..256192e --- /dev/null +++ b/meshmind/cli/__init__.py @@ -0,0 +1 @@ +"""MeshMind CLI package.""" diff --git a/meshmind/cli/__inti__.py b/meshmind/cli/__inti__.py deleted file mode 100644 index e69de29..0000000 diff --git a/meshmind/cli/plugin_stubs/demo_documentation/plugin.yaml b/meshmind/cli/plugin_stubs/demo_documentation/plugin.yaml new file mode 100644 index 0000000..ad1311e --- /dev/null +++ b/meshmind/cli/plugin_stubs/demo_documentation/plugin.yaml @@ -0,0 +1,13 @@ +id: demo_documentation +name: Demo Documentation +capabilities: + - documentation + - writing + - editing +functions: + - name: write_documentation + description: Generate clear documentation, user guides, or API reference. + parameters: {} + - name: improve_readability + description: Rewrite text to make it easier to understand and scan. + parameters: {} diff --git a/meshmind/cli/plugin_stubs/demo_documentation/prompts/system_prompt.txt b/meshmind/cli/plugin_stubs/demo_documentation/prompts/system_prompt.txt new file mode 100644 index 0000000..e08d807 --- /dev/null +++ b/meshmind/cli/plugin_stubs/demo_documentation/prompts/system_prompt.txt @@ -0,0 +1 @@ +You are a documentation specialist. Produce clear, concise guides, API reference, and examples with a reader-first approach. diff --git a/meshmind/cli/plugin_stubs/demo_research/plugin.yaml b/meshmind/cli/plugin_stubs/demo_research/plugin.yaml new file mode 100644 index 0000000..4a0d8a7 --- /dev/null +++ b/meshmind/cli/plugin_stubs/demo_research/plugin.yaml @@ -0,0 +1,13 @@ +id: demo_research +name: Demo Research +capabilities: + - research + - analysis + - summarization +functions: + - name: research_topic + description: Investigate a topic and summarize key findings. + parameters: {} + - name: extract_insights + description: Extract the most important insights from a body of text. + parameters: {} diff --git a/meshmind/cli/plugin_stubs/demo_research/prompts/system_prompt.txt b/meshmind/cli/plugin_stubs/demo_research/prompts/system_prompt.txt new file mode 100644 index 0000000..1bcbfdf --- /dev/null +++ b/meshmind/cli/plugin_stubs/demo_research/prompts/system_prompt.txt @@ -0,0 +1 @@ +You are a researcher assistant. Gather relevant information, analyze it critically, and summarize your findings in a useful way. diff --git a/meshmind/config/schema.py b/meshmind/config/schema.py index afa963f..9ac1a4c 100644 --- a/meshmind/config/schema.py +++ b/meshmind/config/schema.py @@ -59,6 +59,7 @@ class DefaultsConfig(BaseModel): model: str = "gemma4" timeout: int = 60 retries: int = 1 + capability_keywords: dict[str, list[str]] = Field(default_factory=dict) class PluginReference(BaseModel): diff --git a/meshmind/core/node.py b/meshmind/core/node.py index 124c1ea..6d2b68c 100644 --- a/meshmind/core/node.py +++ b/meshmind/core/node.py @@ -250,6 +250,7 @@ def __init__( registry=self.registry, ai_engine=self.ai_engine if use_ai else None, event_logger=self._log_event, + capability_keywords=config.get("capability_keywords"), ) self.discovery = MeshDiscovery( diff --git a/meshmind/core/orchestrator.py b/meshmind/core/orchestrator.py index a287fde..9b0f213 100644 --- a/meshmind/core/orchestrator.py +++ b/meshmind/core/orchestrator.py @@ -139,6 +139,7 @@ def __init__( ai_engine=None, max_retries: int = 0, event_logger=None, + capability_keywords: dict[str, list[str]] | None = None, ) -> None: self.node_id = node_id self.node_name = node_name @@ -148,6 +149,7 @@ def __init__( self.event_logger = event_logger self.traces: list[QueryTrace] = [] self._max_traces = 100 + self._capability_keywords = capability_keywords def _log_event(self, event_type: str, data: dict[str, Any]) -> None: if callable(self.event_logger): @@ -186,7 +188,7 @@ async def _classify_and_route(self, query: str) -> list[dict]: except Exception: logger.warning("AI classification failed, falling back to keywords") - return build_routing_plan(self.registry, query, self.node_id) + return build_routing_plan(self.registry, query, self.node_id, self._capability_keywords) async def process_query(self, query: str) -> tuple[str, QueryTrace]: """Process a user query by routing to specialized nodes and aggregating responses. diff --git a/meshmind/sdk/mesh.py b/meshmind/sdk/mesh.py index f9319e3..ef364ec 100644 --- a/meshmind/sdk/mesh.py +++ b/meshmind/sdk/mesh.py @@ -122,6 +122,7 @@ def __init__( manual_peers: list[dict] | None = None, default_model: str = "gemma4", dev_mode: bool | None = None, + capability_keywords: dict[str, list[str]] | None = None, ) -> None: self.name = name self.discovery = discovery @@ -138,6 +139,7 @@ def __init__( self._running = False self._event_handlers: dict[str, list[Callable]] = {} self._config_dir: Path = Path(".") + self._capability_keywords = capability_keywords or {} @classmethod def from_yaml(cls, path: str | Path) -> "Mesh": @@ -152,6 +154,7 @@ def from_yaml(cls, path: str | Path) -> "Mesh": manual_peers=peers, default_model=config.defaults.model, dev_mode=None, + capability_keywords=config.defaults.capability_keywords, ) mesh._config_dir = path.parent @@ -235,6 +238,10 @@ async def start(self) -> None: + knowledge_context ) + # Add mesh-wide capability keywords to node config + if self._capability_keywords: + config["capability_keywords"] = self._capability_keywords + node = MeshNode( node_info=node_info, config=config, diff --git a/my-project/.meshmind/repl_history b/my-project/.meshmind/repl_history new file mode 100644 index 0000000..0d7fd40 --- /dev/null +++ b/my-project/.meshmind/repl_history @@ -0,0 +1,68 @@ + +# 2026-04-20 11:27:03.556918 ++python -m venv venv-test ++.\venv-test\Scripts\Activate.ps1 ++python -m pip install --upgrade pip ++python -m pip install meshmind==0.1.1 ++meshmind --version + +# 2026-04-20 12:19:55.876072 ++ meshmind plugin install demo_documentation ++meshmind plugin install demo_research + +# 2026-04-20 12:32:16.012494 ++hi + +# 2026-04-20 12:40:28.008274 ++hiii which plugins are there + +# 2026-04-20 12:44:55.592211 ++What tools do you have available? + +# 2026-04-20 12:50:44.647563 ++Write a short guide on how to install Python packages + +# 2026-04-20 12:52:01.938719 ++hi + +# 2026-04-20 12:52:13.162441 ++ + +# 2026-04-20 12:57:08.104379 ++hi + +# 2026-04-20 12:58:16.572155 ++What tools do you have available? + +# 2026-04-20 12:58:59.034871 ++what is cg + +# 2026-04-20 12:59:10.187850 ++what is dsa + +# 2026-04-20 12:59:22.030278 ++dsa + +# 2026-04-20 13:00:39.975381 ++what other plugins are there in the meshmind + +# 2026-04-20 13:03:03.884260 ++Research the benefits of renewable energy + +# 2026-04-20 13:24:54.566450 ++Research renewable energy AND write documentation about solar panels + +# 2026-04-20 13:27:04.002920 ++hu + +# 2026-04-20 13:35:17.967465 ++hi + +# 2026-04-20 13:36:03.873971 ++Research renewable energy AND write documentation about solar panels + +# 2026-04-20 13:38:40.568903 ++write a short poem + +# 2026-04-20 14:12:39.308336 ++hi diff --git a/my-project/meshmind.yaml b/my-project/meshmind.yaml index 34316b8..7bd2cef 100644 --- a/my-project/meshmind.yaml +++ b/my-project/meshmind.yaml @@ -12,10 +12,39 @@ mesh: # - host: "192.168.1.10" # port: 8401 -defaults: - model: 'gemma3:1b' # Lower-memory Gemma model for local development + defaults: + model: 'llama3.2:latest' # Model with tool support timeout: 60 # Query timeout in seconds retries: 1 # Retry failed sub-queries once + capability_keywords: + research: + - research + - investigate + - study + - analyze + - survey + analysis: + - analysis + - analyze + - examine + - evaluate + summarization: + - summary + - summarize + - brief + - concise + documentation: + - documentation + - document + - guide + - manual + - write + - writing + writing: + - write + - writing + - compose + - draft nodes: # ------------------------------------ @@ -23,7 +52,7 @@ nodes: # ------------------------------------ assistant: type: 'specialist' - # model: "gemma3:1b" # Override default model + model: "llama3.2:latest" port: 8401 system_prompt: | You are a helpful assistant specializing in research and analysis. @@ -38,21 +67,40 @@ nodes: knowledge: - ./data/knowledge.json - # Add more specialist nodes as needed: - # writer: - # type: "specialist" - # port: 8402 - # system_prompt: "You are a technical writer..." - # capabilities: - # - "writing" - # - "documentation" + documentation_specialist: + type: 'specialist' + model: "llama3.2:latest" + port: 8402 + plugin: demo_documentation + capabilities: + - 'documentation' + - 'writing' + knowledge_domains: + - 'documentation' + system_prompt: | + You are a documentation specialist. Use the documentation plugin to generate clear guides, examples, and API reference. + + research_specialist: + type: 'specialist' + model: "llama3.2:latest" + port: 8405 + plugin: demo_research + capabilities: + - 'research' + - 'analysis' + - 'summarization' + knowledge_domains: + - 'research' + system_prompt: | + You are a research specialist. Use the research plugin to investigate topics and summarize findings. # ------------------------------------ # Coordinator - routes queries and aggregates # ------------------------------------ coordinator: type: 'coordinator' + model: 'llama3.2:latest' port: 8403 ui: true # Enable web dashboard - ui_port: 9000 # Dashboard at http://localhost:9080 + ui_port: 9000 # Dashboard at http://localhost:9000 diff --git a/pyproject.toml b/pyproject.toml index ff9412c..1e0274b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,54 +1,71 @@ -[project] -name = "meshmind" -version = "0.1.1" -description = "Orchestrate local LLMs across devices with no cloud dependency" -readme = "README.md" -requires-python = ">=3.11" -license = {text = "Apache-2.0"} -classifiers = [ - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", -] - -dependencies = [ - "zeroconf>=0.131.0", - "ollama>=0.4.0", - "fastapi>=0.111.0", - "uvicorn>=0.30.0", - "websockets>=12.0", - "pyyaml>=6.0", - "pydantic>=2.7", - "click>=8.1", - "prompt-toolkit>=3.0.43", - "rich>=13.7.0", -] - -[project.optional-dependencies] -dev = [ - "pytest>=8.0", - "pytest-asyncio>=0.23", - "build>=1.2.0", -] -mcp = [ - "mcp>=1.2.0", -] - -[project.scripts] -meshmind = "meshmind.cli.main:cli" - -[tool.setuptools.packages.find] -include = ["meshmind*"] - -[tool.setuptools.package-data] -meshmind = [ - "knowledge/*.json", - "ui/template/*.html", - "ui/static/**/*", - "cli/templates/*.tmpl", - "cli/presets/*.yaml", - "cli/plugin_stubs/**/*.yaml", - "cli/plugin_stubs/**/*.txt", - "cli/plugin_stubs/**/*.md", -] +[build-system] +requires = ["setuptools>=69", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "meshmind" +version = "0.1.1" +description = "Orchestrate local LLMs across devices with no cloud dependency" +readme = "README.md" +requires-python = ">=3.11" +license = "Apache-2.0" +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +keywords = ["llm", "ollama", "fastapi", "local-first", "distributed-systems", "agent", "plugins"] +authors = [{name = "Nexarion Distributed AI"}] + +dependencies = [ + "zeroconf>=0.131.0", + "ollama>=0.4.0", + "fastapi>=0.111.0", + "uvicorn>=0.30.0", + "websockets>=12.0", + "pyyaml>=6.0", + "pydantic>=2.7", + "click>=8.1", + "prompt-toolkit>=3.0.43", + "rich>=13.7.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8.0", + "pytest-asyncio>=0.23", + "build>=1.2.0", + "twine>=5.0.0", +] +mcp = [ + "mcp>=1.2.0", +] + +[project.scripts] +meshmind = "meshmind.cli.main:cli" + +[project.urls] +Homepage = "https://github.com/Nexarion-Distributed-AI/MeshMind" +Repository = "https://github.com/Nexarion-Distributed-AI/MeshMind" +Issues = "https://github.com/Nexarion-Distributed-AI/MeshMind/issues" +Changelog = "https://github.com/Nexarion-Distributed-AI/MeshMind/blob/main/CHANGELOG.md" +Documentation = "https://github.com/Nexarion-Distributed-AI/MeshMind/tree/main/docs" + +[tool.setuptools] +include-package-data = true +license-files = ["LICENSE"] + +[tool.setuptools.packages.find] +include = ["meshmind*"] + +[tool.setuptools.package-data] +meshmind = [ + "knowledge/*.json", + "ui/template/*.html", + "ui/static/**/*", + "cli/templates/*.tmpl", + "cli/presets/*.yaml", + "cli/plugin_stubs/**/*.yaml", + "cli/plugin_stubs/**/*.txt", + "cli/plugin_stubs/**/*.md", +] diff --git a/shivam/data/knowledge.json b/shivam/data/knowledge.json new file mode 100644 index 0000000..f0073ce --- /dev/null +++ b/shivam/data/knowledge.json @@ -0,0 +1,7 @@ +{ + "project_name": "shivam", + "topics": [ + "Replace with topic areas this mesh should emphasize." + ], + "conventions": "Short conventions and style notes editors can follow when answering (tone, citation, formatting)." +} diff --git a/shivam/meshmind.yaml b/shivam/meshmind.yaml new file mode 100644 index 0000000..cf882ed --- /dev/null +++ b/shivam/meshmind.yaml @@ -0,0 +1,58 @@ +# MeshMind Configuration +# Docs: https://github.com/meshmind/meshmind +# +# Define your mesh of AI nodes below. +# Run `meshmind up` to start all nodes. +# Run `meshmind config validate` to check this file. + +mesh: + name: "shivam" + discovery: "mdns" # "mdns" (auto-detect peers) or "manual" (static list) + # peers: # Only needed for manual discovery + # - host: "192.168.1.10" + # port: 8401 + +defaults: + model: "gemma3:1b" # Default model for all nodes (any Ollama model works) + timeout: 60 # Query timeout in seconds + retries: 1 # Retry failed sub-queries once + +nodes: + # ------------------------------------ + # Specialist Node - handles a specific domain + # ------------------------------------ + shivam-assistant: + type: "specialist" + # model: "gemma3:1b" # Override default model + port: 8401 + system_prompt: | + You are a helpful assistant specializing in research and analysis. + Provide detailed, accurate, and well-structured answers. + capabilities: + - "research" + - "analysis" + - "summarization" + knowledge_domains: + - "research" + - "analysis" + knowledge: + - ./data/knowledge.json + + # Add more specialist nodes as needed: + # writer: + # type: "specialist" + # port: 8402 + # system_prompt: "You are a technical writer..." + # capabilities: + # - "writing" + # - "documentation" + + # ------------------------------------ + # Coordinator - routes queries and aggregates + # ------------------------------------ + shivam-coordinator: + type: "coordinator" + port: 8403 + ui: true # Enable web dashboard + ui_port: 8080 # Dashboard at http://localhost:8080 + diff --git a/tests/test_plugin_init_ux.py b/tests/test_plugin_init_ux.py index 467d54d..376bbc7 100644 --- a/tests/test_plugin_init_ux.py +++ b/tests/test_plugin_init_ux.py @@ -37,6 +37,8 @@ def test_iter_bundled_plugin_ids_includes_demos() -> None: ids = iter_bundled_plugin_ids() assert "demo_review" in ids assert "demo_security" in ids + assert "demo_documentation" in ids + assert "demo_research" in ids def test_install_one_bundled_plugin_copies_stub(tmp_path, monkeypatch) -> None: @@ -114,6 +116,9 @@ def test_plugin_catalog_cli_lists_bundled(args: list[str]) -> None: r = CliRunner().invoke(cli, args) assert r.exit_code == 0 assert "demo_review" in r.output + assert "demo_security" in r.output + assert "demo_documentation" in r.output + assert "demo_research" in r.output def test_apply_plugin_file_not_found_message_includes_sync_hint(tmp_path, monkeypatch) -> None: From a710afee2978659713ad7ebe1f00ca52e87e5caa Mon Sep 17 00:00:00 2001 From: Arnav Chhabra <65032719+Halleys123@users.noreply.github.com> Date: Mon, 20 Apr 2026 22:57:30 +0530 Subject: [PATCH 2/2] Delete .tmp/manualdir/foo.json The file was empty and not used, so removed the file --- .tmp/manualdir/foo.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .tmp/manualdir/foo.json diff --git a/.tmp/manualdir/foo.json b/.tmp/manualdir/foo.json deleted file mode 100644 index c1b0730..0000000 --- a/.tmp/manualdir/foo.json +++ /dev/null @@ -1 +0,0 @@ -x \ No newline at end of file