InfoMesh β κΈ°μ μ€ν λ° μ½λ© κ·μΉ
λ μ΄μ΄
κΈ°μ
λΉκ³
μΈμ΄
Python 3.12+
μ΅μ λ¬Έλ² μ¬μ© (νμ
ννΈ, match, type λ¬Έ, StrEnum, TypeVar κΈ°λ³Έκ° λ±)
P2P λ€νΈμν¬
libp2p (py-libp2p)
DHT, NAT νΈλλ²μ€, μνΈν λ΄μ₯
DHT
Kademlia
κ²μ¦λ λΆμ° ν΄μ ν
μ΄λΈ (μΈλ±μ€ + ν¬λ‘€λ§ μ‘°μ¨)
ν¬λ‘€λ§
httpx + asyncio
λΉλκΈ° κ³ μ±λ₯ HTTP ν΄λΌμ΄μΈνΈ
HTML νμ±
trafilatura
λ³Έλ¬Έ μΆμΆ μ νλ μ΅κ³
ν€μλ μΈλ±μ€
SQLite FTS5
μ€μΉ λΆνμ, μλ² λλ μ λ¬Έ κ²μ
λ²‘ν° μΈλ±μ€
ChromaDB
μλ§¨ν± κ²μ, μλ² λ© μ μ₯
MCP μλ²
mcp-python-sdk
VS Code / Claude μ°λ
κ΄λ¦¬ API
FastAPI
λ‘컬 μν μ‘°ν/μ€μ λ³κ²½
μ§λ ¬ν
msgpack
JSONλ³΄λ€ λΉ λ₯΄κ³ μμ
μμΆ
zstd
λ 벨 μ‘°μ κ°λ₯ μμΆ; μ μ¬ λ¬Έμμ λμ
λ리 λͺ¨λ μ§μ
λ‘컬 LLM
ollama / llama.cpp
μ νμ λ‘컬 μμ½ (Qwen 2.5, Llama 3.x λ±)
λ‘κΉ
structlog
λͺ¨λ λΌμ΄λΈλ¬λ¦¬ μ½λμ ꡬ쑰νλ λ‘κΉ
ν¨ν€μ§ λ§€λμ
uv
λΉ λ₯Έ Python ν¨ν€μ§/νλ‘μ νΈ λ§€λμ (pip/venv λ체)
μ νμ / ν΄λ°± μμ‘΄μ±
ν¨ν€μ§
μ¬μ© μμ
BeautifulSoup4
trafilatura μ€ν¨ μ HTML νμ± ν΄λ°±
vLLM
κ³ μ±λ₯ GPU μΆλ‘ (μ¬λΌλ§/llama.cpp λμ)
sentence-transformers
ChromaDB λ²‘ν° μΈλ±μ€μ© μλ² λ© μμ±
infomesh/
βββ pyproject.toml
βββ infomesh/
β βββ __init__.py # ν¨ν€μ§ 루νΈ
β βββ __main__.py # CLI μ§μ
μ
β βββ config.py # μ€μ κ΄λ¦¬
β βββ services.py # μ€μ AppContext + index_document μ€μΌμ€νΈλ μ΄μ
β βββ p2p/ # P2P λ€νΈμν¬ λ μ΄μ΄
β β βββ node.py # νΌμ΄ λ©μΈ νλ‘μΈμ€
β β βββ dht.py # Kademlia DHT
β β βββ routing.py # 쿼리 λΌμ°ν
β β βββ replication.py # λ¬Έμ/μΈλ±μ€ 볡μ
β β βββ protocol.py # λ©μμ§ νλ‘ν μ½ μ μ
β βββ crawler/ # μΉ ν¬λ‘€λ¬
β β βββ worker.py # λΉλκΈ° ν¬λ‘€λ§ μ컀
β β βββ scheduler.py # URL ν λΉ (DHT κΈ°λ°)
β β βββ parser.py # HTML β ν
μ€νΈ μΆμΆ
β β βββ robots.py # robots.txt μ€μ
β β βββ dedup.py # μ€λ³΅ μ κ±° νμ΄νλΌμΈ (URL, SHA-256, SimHash)
β β βββ seeds.py # μλ URL κ΄λ¦¬ λ° μΉ΄ν
κ³ λ¦¬ μ ν
β β βββ crawl_loop.py # μ°μ μλ-ν¬λ‘€λ§ 루ν (services.pyμμ μΆμΆ)
β βββ index/ # κ²μ μΈλ±μ€
β β βββ local_store.py # SQLite FTS5 λ‘컬 μΈλ±μ€
β β βββ vector_store.py # ChromaDB λ²‘ν° μΈλ±μ€
β β βββ distributed.py # DHT μμΈλ±μ€ λ°ν/μ§μ
β β βββ ranking.py # BM25 + μ μ λ + μ λ’°λ
β βββ search/ # κ²μ μμ§
β β βββ query.py # 쿼리 νμ± + λΆμ° κ²μ μ€μΌμ€νΈλ μ΄μ
β β βββ merge.py # λ€μ€ λ
Έλ κ²°κ³Ό λ³ν©
β βββ mcp/ # MCP μλ² (SRP: 4κ° λͺ¨λλ‘ λΆλ¦¬)
β β βββ server.py # μ°κ²° λ μ΄μ΄: Server μμ±, ν΄ λμ€ν¨μΉ, μ€νκΈ°
β β βββ tools.py # ν΄ μ€ν€λ§ μ μ + νν° μΆμΆ
β β βββ handlers.py # ν΄ νΈλ€λ¬ ꡬν (handle_search λ±)
β β βββ session.py # SearchSession, AnalyticsTracker, WebhookRegistry
β βββ api/ # λ‘컬 κ΄λ¦¬ API
β β βββ local_api.py # FastAPI (μν μ‘°ν, μ€μ λ³κ²½)
β βββ credits/ # μΈμΌν°λΈ μμ€ν
β β βββ types.py # ActionType, CreditState, λ°μ΄ν°ν΄λμ€ (ledger.pyμμ μΆμΆ)
β β βββ ledger.py # SQLite κΈ°λ° ν¬λ λ§ μμ₯ (types.pyμμ νμ
μν¬νΈ)
β βββ trust/ # μ λ’° & 무결μ±
β β βββ attestation.py # μ½ν
μΈ μ¦λͺ
μ²΄μΈ (μλͺ
, κ²μ¦)
β β βββ audit.py # λλ€ κ°μ¬ μμ€ν
β β βββ scoring.py # ν΅ν© μ λ’° μ μ κ³μ°
β βββ summarizer/ # λ‘컬 LLM μμ½
β β βββ engine.py # LLM λ°±μλ μΆμν (ollama, llama.cpp)
β β βββ summarize.py # μ½ν
μΈ μμ½ νμ΄νλΌμΈ
β β βββ verify.py # μμ½ κ²μ¦ (ν€ν©νΈ μ΅μ»€λ§, NLI)
β βββ compression/ # λ°μ΄ν° μμΆ
β βββ zstd.py # zstd μμΆ + λμ
λ리 μ§μ
βββ bootstrap/
β βββ nodes.json # λΆνΈμ€νΈλ© λ
Έλ λͺ©λ‘
βββ seeds/ # λ΄μ₯ μλ URL λͺ©λ‘
β βββ tech-docs.txt # κΈ°μ λ¬Έμ URL
β βββ academic.txt # νμ λ
Όλ¬Έ μμ€ URL
β βββ encyclopedia.txt # λ°±κ³Όμ¬μ URL
βββ tests/
β βββ conftest.py # 곡μ ν½μ€μ²
β βββ test_dht.py
β βββ test_crawler.py
β βββ test_index.py
β βββ test_search.py
β βββ test_credits.py
β βββ test_trust.py
β βββ test_summarizer.py
β βββ test_mcp.py
β βββ test_services.py # μλΉμ€ λ μ΄μ΄ ν
μ€νΈ
β βββ test_mcp_handlers.py # MCP νΈλ€λ¬ ν
μ€νΈ
βββ docs/
μΈμ΄ : λͺ¨λ μμ€ μ½λ, μ£Όμ, docstring, μ»€λ° λ©μμ§, PRμ μμ΄ λ‘ μμ±.
Python λ²μ : 3.12+ β μ΅μ λ¬Έλ² μ¬μ© (match/case, type λ¬Έ, StrEnum, TypeVar κΈ°λ³Έκ°).
λΉλκΈ° μ°μ : λͺ¨λ I/O λ°μ΄λ μ½λλ async/await + asyncio μ¬μ©. μ΄λ²€νΈ 루νμμ λΈλ‘νΉ I/O κΈμ§.
νμ
ννΈ : λͺ¨λ κ³΅κ° ν¨μμ ν΄λμ€ μμ±μ νμ. μ λ°© μ°Έμ‘° μ from __future__ import annotations μ¬μ©.
ν¬λ§€ν°: ruff format (κΈ°λ³Έ μ€μ , μ€ κΈΈμ΄ 88).
λ¦°ν°: ruff β select = ["E", "F", "I", "UP", "B", "SIM"].
μν¬νΈ μμ: stdlib β μλνν° β λ‘컬 (ruff/isort μ μ©).
os.path λμ pathlib.Path μ νΈ.
λμ
κ·μΉ
μμ
λͺ¨λ/ν¨ν€μ§
snake_case
local_store.py
ν΄λμ€
PascalCase
SearchResult
ν¨μ/λ©μλ/λ³μ
snake_case
parse_query()
μμ
UPPER_SNAKE_CASE
MAX_RETRIES
λΉκ³΅κ° λ©€λ²
λ¨μΌ λ°μ€
_internal_state
ꡬ체μ μμΈ νμ
μ¬μ© β λΉ except: κΈμ§.
structlog λλ stdlib logging μ¬μ© β λΌμ΄λΈλ¬λ¦¬ μ½λμμ print() κΈμ§.
λ€νΈμν¬/IO μ€ν¨ μ μ§μ λ°±μ€ν(exponential backoff)λ‘ μ¬μλ.
νλ μμν¬: pytest + pytest-asyncio (λΉλκΈ° ν
μ€νΈ).
ν
μ€νΈ νμΌμ μμ€ λ μ΄μμ λ―Έλ¬λ§: infomesh/p2p/dht.py β tests/test_dht.py.
λͺ¨λ κ³΅κ° ν¨μ/λ©μλμ μ΅μ νλμ ν
μ€νΈ.
μΈλΌμΈ μ
μ
λ³΄λ€ fixtureμ factory μ¬μ©.
4. μμ‘΄μ± & ν¨ν€μ§ κ΄λ¦¬
uvλ₯Ό λͺ¨λ μμ‘΄μ± ν΄κ²°, κ°μ νκ²½, νλ‘μ νΈ κ΄λ¦¬μ μ¬μ©.
λͺ¨λ μμ‘΄μ±μ pyproject.tomlμ [project.dependencies]μ μ μΈ.
κ°λ° μμ‘΄μ±μ [dependency-groups] (PEP 735) λλ [project.optional-dependencies.dev]μ μ μΈ.
μ΅μ λ²μ λ§ κ³ μ (μ: httpx>=0.27), μ νν λ²μ κ³ μ μμ.
λ½ νμΌ: uv.lock β μ¬ν κ°λ₯ν λΉλλ₯Ό μν΄ μ μ₯μμ 컀λ°.
requirements.txt μμ, pip μμ β uv λͺ
λ Ήλ§ μ¬μ©.
uv sync # λͺ¨λ μμ‘΄μ± μ€μΉ (.venv μλ μμ±)
uv sync --dev # κ°λ° μμ‘΄μ± ν¬ν¨ μ€μΉ
uv add < package> # μ μμ‘΄μ± μΆκ°
uv add --dev < pkg> # κ°λ° μμ‘΄μ± μΆκ°
uv run < command> # νλ‘μ νΈ νκ²½μμ λͺ
λ Ή μ€ν
uv run pytest # ν
μ€νΈ μ€ν
uv run infomesh start # μ ν리μΌμ΄μ
μ€ν
κ΄λ ¨ λ¬Έμ: κ°μ Β· μν€ν
μ² Β· ν¬λ λ§ μμ€ν
Β· λ²μ κ³ λ €μ¬ν Β· μ λ’° & λ¬΄κ²°μ± Β· 보μ κ°μ¬ Β· μ½μ λμ보λ Β· MCP μ°λ Β· λ°°ν¬ Β· FAQ