github Python analyzed 2cfa561

jaymeklein/embedbase

github

Local-first document embedding and retrieval platform with a REST API and MCP server for LLM agents. Supports hybrid BM25 + semantic search across workspaces and collections, with pluggable parsers, embedders, and vector stores.

maintainer
jaymeklein
license
first seen
2026-06-04
last seen
2026-08-13
releases · 30d
0
short id

Drift inferred · capture-to-capture

No drift recorded — single capability capture; advisories appear once its surface changes.

capabilities 30 tools
transport stdio · streamable-http counts 30 tools · 0 res · 0 prompts permission surface via code analysis

tools

  • assign_tag
  • confirm_original_upload
  • confirm_upload
  • create_collection
  • create_tag
  • create_workspace
  • delete_collection
  • delete_document
  • delete_tag
  • delete_workspace
  • download_document
  • get_checksum
  • get_document_chunks
  • get_document_status
  • get_ingestion_stats
  • get_rate_limit
  • ingest_document
  • list_documents
  • list_ingestion_jobs
  • list_tags
  • list_workspaces
  • merge_tags
  • reprocess_document
  • request_original_upload
  • request_upload
  • search_documents
  • unassign_tag
  • update_collection
  • update_tag
  • update_workspace
skills & danger signals github-tarball
prompt-surface shipped agent-instruction files + hidden-content / dangerous-code findings — quoted from the analyzed source

analyzed commit 2cfa561 · analyzer v33 · 2w ago

skills & prompt files 2

code evidence vHEAD · github-tarball
evidence-backed findings quoted directly from the published source artifact — not inferred

code files: 292

filesystem 23

  • fs jaymeklein-embedbase-2cfa561/api/adapters/parsers/docling_adapter.py :24 from pathlib import Path
  • fs jaymeklein-embedbase-2cfa561/api/adapters/parsers/markdown.py :58 with open(file_path, encoding="utf-8", errors="replace") as fh:
  • fs jaymeklein-embedbase-2cfa561/api/adapters/parsers/pdf.py :66 with fitz.open(file_path) as doc:
  • fs jaymeklein-embedbase-2cfa561/api/adapters/parsers/txt.py :27 with open(file_path, "rb") as fh:
  • fs jaymeklein-embedbase-2cfa561/api/db.py :13 from pathlib import Path
  • fs jaymeklein-embedbase-2cfa561/api/main.py :3 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/api/scripts/fetch_reranker_model.py :35 with open(os.path.join(DEST, name), "wb") as fh:
  • fs jaymeklein-embedbase-2cfa561/api/services/config_env.py :14 from pathlib import Path
  • fs jaymeklein-embedbase-2cfa561/api/services/config_service.py :25 from pathlib import Path
  • fs jaymeklein-embedbase-2cfa561/api/services/documents.py :13 from pathlib import Path
  • fs jaymeklein-embedbase-2cfa561/api/services/storage.py :19 import shutil
  • fs jaymeklein-embedbase-2cfa561/api/services/upload.py :12 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/scripts/check_ports.py :20 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/scripts/export_openapi.py :12 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/tests/fixtures/docling/generate_fixtures.py :20 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_ingestion.py :9 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/tests/smoke/test_smoke.py :8 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_migrations.py :10 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_parsers.py :17 doc = fitz.open()
  • fs (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_parsers_docling.py :13 from pathlib import Path
  • fs (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_pdf_progress.py :11 doc = fitz.open()
  • fs jaymeklein-embedbase-2cfa561/worker/config.py :6 from pathlib import Path
  • fs jaymeklein-embedbase-2cfa561/worker/tasks.py :685 open (0) on a redis error so a redis blip can't wedge ingestion shut."""

network 21

  • net jaymeklein-embedbase-2cfa561/api/adapters/embeddings/errors.py :5 import httpx
  • net jaymeklein-embedbase-2cfa561/api/adapters/embeddings/gemini.py :1 import httpx
  • net jaymeklein-embedbase-2cfa561/api/adapters/embeddings/ollama.py :3 import httpx
  • net jaymeklein-embedbase-2cfa561/api/adapters/embeddings/openai_compat.py :1 import httpx
  • net jaymeklein-embedbase-2cfa561/api/adapters/llm_chat.py :46 import httpx
  • net jaymeklein-embedbase-2cfa561/api/port_utils.py :3 import socket
  • net (weak) jaymeklein-embedbase-2cfa561/api/scripts/fetch_reranker_model.py :15 import requests
  • net jaymeklein-embedbase-2cfa561/api/services/config_reload.py :20 import socket
  • net jaymeklein-embedbase-2cfa561/api/services/health.py :9 import socket
  • net (weak) jaymeklein-embedbase-2cfa561/tests/conftest.py :7 from httpx import ASGITransport, AsyncClient
  • net (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_mcp.py :23 from httpx import ASGITransport, AsyncClient
  • net (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_search.py :6 from httpx import ASGITransport, AsyncClient
  • net (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_search_e2e.py :18 from httpx import ASGITransport, AsyncClient
  • net (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_config_reload.py :7 import socket
  • net (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_embeddings.py :14 import httpx
  • net (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_health_service.py :93 import socket as socket_mod
  • net (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_llm_chat.py :6 model pickers. No network — ``post_json`` / ``httpx.*`` are patched.
  • net (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_port_utils.py :27 with patch("socket.socket", return_value=_busy_sock()):
  • net (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_rate_limit.py :11 import httpx
  • net (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_storage.py :8 from urllib.parse import urlparse
  • net jaymeklein-embedbase-2cfa561/worker/tasks.py :615 detect a 429, e.g. Gemini) or an ``httpx.HTTPStatusError`` carrying status 429

secrets 2

  • secrets (weak) jaymeklein-embedbase-2cfa561/tests/conftest.py :15 os.environ["MASTER_API_KEY"] = "test-master-key-for-testing-only"
  • secrets (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_pgvector_live.py :47 "password": os.environ.get("EMBEDBASE_TEST_PG_PASSWORD", ""),

database 86

  • db jaymeklein-embedbase-2cfa561/api/adapters/vector_store/pgvector.py :212 import asyncpg
  • db jaymeklein-embedbase-2cfa561/api/alembic/env.py :19 from sqlalchemy import pool
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0001_initial_schema.py :13 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0002_add_processing_started_at.py :14 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0003_add_documents_status.py :14 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0004_add_tags.py :15 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0005_add_documents_embedding_model.py :14 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0006_add_documents_storage_backend.py :15 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0007_add_documents_expires_at.py :17 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0008_add_users_and_permissions.py :20 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0009_add_user_login.py :25 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0010_add_users_rate_limit_rpm.py :17 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0011_users_email_nullable.py :16 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/alembic/versions/0012_add_documents_original_columns.py :19 import sqlalchemy as sa
  • db jaymeklein-embedbase-2cfa561/api/db.py :15 from sqlalchemy import event
  • db jaymeklein-embedbase-2cfa561/api/dependencies.py :5 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/main.py :184 import redis as redis_lib
  • db jaymeklein-embedbase-2cfa561/api/routers/auth.py :15 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/collections.py :2 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/documents.py :12 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/graph.py :9 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/indexing.py :10 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/jobs.py :15 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/search.py :4 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/tags.py :15 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/users.py :12 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/workspaces.py :2 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/routers/ws.py :25 import redis.asyncio as aioredis
  • db jaymeklein-embedbase-2cfa561/api/services/access.py :33 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/services/auth.py :36 from sqlalchemy import select, update
  • db jaymeklein-embedbase-2cfa561/api/services/collections.py :15 from sqlalchemy import delete, func, insert, select, update
  • db jaymeklein-embedbase-2cfa561/api/services/document_filters.py :22 from sqlalchemy import or_, select
  • db jaymeklein-embedbase-2cfa561/api/services/documents.py :20 from sqlalchemy import and_, delete, func, insert, or_, select, update
  • db jaymeklein-embedbase-2cfa561/api/services/filters.py :17 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/services/graph.py :20 from sqlalchemy import select
  • db jaymeklein-embedbase-2cfa561/api/services/indexing.py :15 from sqlalchemy import select
  • db jaymeklein-embedbase-2cfa561/api/services/job_filters.py :14 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/services/jobs.py :15 from sqlalchemy import func, select
  • db jaymeklein-embedbase-2cfa561/api/services/mcp/tools.py :22 from sqlalchemy.ext.asyncio import AsyncSession
  • db jaymeklein-embedbase-2cfa561/api/services/permissions.py :34 from sqlalchemy import delete, insert, select, update
  • db jaymeklein-embedbase-2cfa561/api/services/search.py :7 from sqlalchemy import select
  • db jaymeklein-embedbase-2cfa561/api/services/tag_bridge.py :26 from sqlalchemy import select
  • db jaymeklein-embedbase-2cfa561/api/services/tags.py :17 from sqlalchemy import Table, delete, func, insert, select, update
  • db jaymeklein-embedbase-2cfa561/api/services/users.py :22 from sqlalchemy import delete, insert, select, update
  • db jaymeklein-embedbase-2cfa561/api/services/workspaces.py :15 from sqlalchemy import delete, func, insert, select, update
  • db jaymeklein-embedbase-2cfa561/api/sql_compat.py :13 from sqlalchemy import Table
  • db jaymeklein-embedbase-2cfa561/api/tables/api_keys.py :1 from sqlalchemy import Column, ForeignKey, Index, String, Table, UniqueConstraint
  • db jaymeklein-embedbase-2cfa561/api/tables/collections.py :1 from sqlalchemy import Column, ForeignKey, Index, String, Table, Text, UniqueConstraint
  • db jaymeklein-embedbase-2cfa561/api/tables/documents.py :1 from sqlalchemy import Column, DateTime, ForeignKey, Index, Integer, String, Table
  • db jaymeklein-embedbase-2cfa561/api/tables/job_records.py :1 from sqlalchemy import Column, DateTime, Integer, String, Table, Text
  • db jaymeklein-embedbase-2cfa561/api/tables/metadata.py :1 from sqlalchemy import MetaData
  • db jaymeklein-embedbase-2cfa561/api/tables/permissions.py :17 from sqlalchemy import Column, ForeignKey, Index, String, Table, UniqueConstraint
  • db jaymeklein-embedbase-2cfa561/api/tables/tags.py :9 from sqlalchemy import (
  • db jaymeklein-embedbase-2cfa561/api/tables/users.py :16 from sqlalchemy import Boolean, Column, Index, Integer, String, Table, UniqueConstraint, false, true
  • db jaymeklein-embedbase-2cfa561/api/tables/workspaces.py :1 from sqlalchemy import Column, String, Table, Text
  • db (weak) jaymeklein-embedbase-2cfa561/tests/conftest.py :8 from sqlalchemy import event as sa_event
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_documents.py :173 from sqlalchemy import update
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_indexing_router.py :8 from sqlalchemy import insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_ingestion.py :16 from sqlalchemy import create_engine, insert, select # noqa: E402
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_jobs.py :110 from sqlalchemy import update
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_mcp.py :24 from sqlalchemy import event as sa_event
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_search.py :7 from sqlalchemy import event as sa_event
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_search_e2e.py :19 from sqlalchemy import event as sa_event
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_users.py :271 from sqlalchemy import select
  • db (weak) jaymeklein-embedbase-2cfa561/tests/integration/test_ws.py :14 from sqlalchemy import event as sa_event
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_auth.py :58 from sqlalchemy import insert, select # noqa: E402
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_collections_svc.py :5 from sqlalchemy import insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_delete_worker.py :118 from sqlalchemy import create_engine, insert, select
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_documents_service.py :8 from sqlalchemy import insert, select, update
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_ephemeral_ingest.py :17 from sqlalchemy import create_engine, insert, select
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_indexing_service.py :8 from sqlalchemy import insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_ingestion_progress.py :9 from sqlalchemy import create_engine, insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_jobs_service.py :3 from sqlalchemy import insert, select
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_migrations.py :9 import sqlite3
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_permissions.py :5 from sqlalchemy import delete, insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_pgvector_adapter.py :5 tests never import asyncpg or touch a database — they verify the request/response
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_rate_limit.py :13 from sqlalchemy import create_engine, insert, select
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_stale_guard.py :11 from sqlalchemy import create_engine, insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_tag_bridge.py :11 from sqlalchemy import insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_tags_service.py :11 from sqlalchemy import insert, select
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_worker_helpers.py :9 from sqlalchemy import create_engine, insert, select
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_worker_storage_delete.py :8 from sqlalchemy import create_engine, insert
  • db (weak) jaymeklein-embedbase-2cfa561/tests/unit/test_worker_tag_sync.py :10 from sqlalchemy import create_engine, insert
  • db jaymeklein-embedbase-2cfa561/worker/config_reload.py :31 import redis
  • db jaymeklein-embedbase-2cfa561/worker/db.py :16 from sqlalchemy import create_engine, event
  • db jaymeklein-embedbase-2cfa561/worker/tasks.py :19 from sqlalchemy import and_, or_, select, update

tool registrations 30

  • list_workspaces jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :54
  • search_documents jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :65
  • list_documents jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :108
  • ingest_document jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :121
  • request_upload jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :136
  • confirm_upload jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :153
  • request_original_upload jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :161
  • confirm_original_upload jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :175
  • reprocess_document jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :183
  • get_document_status jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :191
  • download_document jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :205
  • get_checksum jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :218
  • get_document_chunks jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :234
  • delete_document jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :253
  • create_workspace jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :265
  • update_workspace jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :276
  • delete_workspace jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :288
  • create_collection jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :296
  • update_collection jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :308
  • delete_collection jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :321
  • list_tags jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :334
  • create_tag jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :342
  • update_tag jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :353
  • delete_tag jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :364
  • merge_tags jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :372
  • assign_tag jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :381
  • unassign_tag jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :400
  • list_ingestion_jobs jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :424
  • get_ingestion_stats jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :441
  • get_rate_limit jaymeklein-embedbase-2cfa561/api/services/mcp/server.py :450

declared dependencies 14

  • fastapi@>=0.136.0,<0.138.0
  • uvicorn@>=0.29.0
  • pydantic@>=2.7.0
  • pydantic-settings@>=2.2.0
  • s@EmailStr (user email validation); pydantic v2 needs v2+.
  • pytest@>=8.0.0
  • pytest-asyncio@>=0.23.0
  • pytest-cov@>=5.0.0
  • httpx@>=0.27.0
  • ruff@>=0.4.0
  • mypy@>=1.10.0
  • types-PyYAML@>=6.0.12
  • types-redis@>=4.6.0
  • moto@>=5.0