Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ jobs:
- name: Lint
run: ruff check src tests

- name: Type Check
run: mypy src

- name: Test
run: pytest
42 changes: 0 additions & 42 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,42 +0,0 @@
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "skillmesh"
version = "0.1.0"
description = "A retrieval-gated skill architecture for LLM agents that scales to hundreds of tools by exposing only the top-K relevant capabilities per request."
readme = "README.md"
requires-python = ">=3.10"
license = { text = "MIT" }
authors = [{ name = "Open Skill Registry Contributors" }]
dependencies = [
"numpy>=1.24",
"PyYAML>=6.0",
"rank-bm25>=0.2.2",
"jsonschema>=4.0",
"chromadb>=0.5.0"
]

[project.optional-dependencies]
dense = ["sentence-transformers>=2.7.0"]
mcp = ["mcp>=1.0.0"]
dev = ["pytest>=8.0", "pytest-cov>=5.0", "ruff>=0.6.0"]

[project.scripts]
skillmesh = "skill_registry_rag.cli:main"
skillmesh-mcp = "skill_registry_rag.mcp_server:main"

[tool.setuptools]
package-dir = {"" = "src"}

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
addopts = "-q"
testpaths = ["tests"]

[tool.ruff]
line-length = 100
target-version = "py310"
2 changes: 1 addition & 1 deletion src/skill_registry_rag/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .backends.memory import InMemoryBackend
from .models import ExpertCard, RetrievalHit, ToolCard
from .registry import load_registry
from .retriever import SkillRetriever
from .retriever import SkillRetriever # type: ignore

__all__ = [
"ExpertCard",
Expand Down
8 changes: 5 additions & 3 deletions src/skill_registry_rag/backends/chroma.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
from pathlib import Path
from typing import Optional

from typing import Any
import numpy as np
from rank_bm25 import BM25Okapi
from rank_bm25 import BM25Okapi # type: ignore

from ..models import ExpertCard, RetrievalHit
from .memory import _tokenize, _rrf
Expand Down Expand Up @@ -44,7 +45,7 @@ def _compose_doc(card: ExpertCard) -> str:

class ChromaBackend:
def __init__(self, *, collection_name: str = "skillmesh_experts", data_dir: str | Path | None = None, ephemeral: bool = False):
import chromadb
import chromadb # type: ignore

self._collection_name = collection_name
self._ephemeral = ephemeral
Expand Down Expand Up @@ -103,13 +104,14 @@ def index(self, cards: list[ExpertCard]) -> None:
batch_size = 500
for i in range(0, len(ids), batch_size):
end = min(i + batch_size, len(ids))
assert self._collection is not None
self._collection.upsert(
ids=ids[i:end],
documents=documents[i:end],
metadatas=metadatas[i:end],
)

def _sparse_scores(self, query: str) -> np.ndarray:
def _sparse_scores(self, query: str) -> np.ndarray[Any, Any]:
n = len(self._cards)
if n == 0:
return np.array([], dtype=np.float32)
Expand Down
13 changes: 7 additions & 6 deletions src/skill_registry_rag/backends/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import re
from typing import Optional

from typing import Any
import numpy as np
from rank_bm25 import BM25Okapi
from rank_bm25 import BM25Okapi # type: ignore # type: ignore

from ..models import ExpertCard, RetrievalHit

Expand All @@ -15,7 +16,7 @@ def _tokenize(text: str) -> list[str]:
return re.findall(r"[a-zA-Z0-9_\.]+", str(text or "").lower())


def _rrf(ranks: list[np.ndarray], n_docs: int, k: int = 60) -> np.ndarray:
def _rrf(ranks: list[np.ndarray[Any, Any]], n_docs: int, k: int = 60) -> np.ndarray[Any, Any]:
scores = np.zeros(n_docs, dtype=np.float32)
for order in ranks:
for rank, idx in enumerate(order, start=1):
Expand All @@ -33,7 +34,7 @@ def __init__(self, *, use_dense: bool = False) -> None:
self._tokens: list[list[str]] = []
self._bm25: Optional[BM25Okapi] = None
self._dense_model = None
self._dense_embeddings: Optional[np.ndarray] = None
self._dense_embeddings: Optional[np.ndarray[Any, Any]] = None

# ------------------------------------------------------------------
# RetrievalBackend interface
Expand Down Expand Up @@ -112,7 +113,7 @@ def _compose_doc(card: ExpertCard) -> str:

def _init_dense(self) -> None:
try:
from sentence_transformers import SentenceTransformer
from sentence_transformers import SentenceTransformer # type: ignore # type: ignore

model = SentenceTransformer("BAAI/bge-small-en-v1.5")
embs = model.encode(self._doc_texts, normalize_embeddings=True)
Expand All @@ -122,7 +123,7 @@ def _init_dense(self) -> None:
self._dense_model = None
self._dense_embeddings = None

def _sparse_scores(self, query: str) -> np.ndarray:
def _sparse_scores(self, query: str) -> np.ndarray[Any, Any]:
n = len(self._cards)
if n == 0:
return np.array([], dtype=np.float32)
Expand All @@ -144,7 +145,7 @@ def _sparse_scores(self, query: str) -> np.ndarray:
overlaps.append((inter / union) if union else 0.0)
return np.asarray(overlaps, dtype=np.float32)

def _dense_scores(self, query: str) -> Optional[np.ndarray]:
def _dense_scores(self, query: str) -> Optional[np.ndarray[Any, Any]]:
if self._dense_model is None or self._dense_embeddings is None:
return None
try:
Expand Down
2 changes: 1 addition & 1 deletion src/skill_registry_rag/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from .adapters import render_claude_context, render_codex_context
from .registry import RegistryError, load_registry
from .retriever import SkillRetriever
from .retriever import SkillRetriever # type: ignore


def _build_parser() -> argparse.ArgumentParser:
Expand Down
Loading