unified-kg-rag-on-aws
CLAUDE.md39 starsChanged 7 days agoApache-2.0View on GitHub
AWS-native Knowledge Graph RAG framework. Reimplements the Microsoft GraphRAG, LightRAG, HippoRAG 2 and RAPTOR methodologies on Bedrock + Neptune + OpenSearch, with DynamoDB for incremental-indexing state. The package is laid out in explicit hexagonal layers so the four RAG methodologies (see Capabilities & CLIs) share one ingestion/indexing/caching/hybrid-search infrastructure and only differ at the algorithm layer. Dependencies point inward. Layers, outermost first — a module imports its own layer and later ones, never an earlier one, and that includes lazy and…
The file
We split this CLAUDE.md into the rules it gives an agent
10 rules. About 0 are common, 6 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 84
Registries over hardcoded dispatch: search strategies register via @register_strategy (adapters/retrieval/strategy_registry.py).
- Distinctive: line 195
Tests/fixtures/eval: use neutral *synthetic* data (generic entities like "Vendor"/"Buyer", made-up amounts).
- Very specific: line 197
Real-corpus tests: keep non-public corpora out of the repo entirely.
- Distinctive: line 237
Treat main as protected shared history.
- Very specific: line 240
Never commit or push directly to
main: Do all work on a topic branch (feat/…, fix/…, docs/…, chore/…) and land it through a Pull Request, … - Distinctive: line 243
One logical change per PR/commit: Keep them small and focused.
- Very specific: line 249
Green before you push: Run uv run pytest (its addopts deselect aws, perf and weekly) and the pre-commit hooks (ruff/black/isort/mypy) …
- Distinctive: line 255
Never merge your own PR without review: when a second maintainer is available.
- Distinctive: line 261
Customer-data check is a hard blocker: Before every commit, grep the staged diff for customer terms (see *No customer data* above).
- Distinctive: line 271
Ask before side-effecting AWS actions (resource creation, real-AWS tests).
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Project Guide for Claude Code
AWS-native Knowledge Graph RAG framework. Reimplements the Microsoft GraphRAG, LightRAG, HippoRAG 2 and RAPTOR methodologies on Bedrock + Neptune + OpenSearch, with DynamoDB for incremental-indexing state.
Architecture (hexagonal / ports & adapters)
The package is laid out in explicit hexagonal layers so the four RAG
methodologies (see Capabilities & CLIs) share one
ingestion/indexing/caching/hybrid-search infrastructure and only differ at
the algorithm layer. Dependencies point inward. Layers, outermost first —
a module imports its own layer and later ones, never an earlier one, and
that includes lazy and TYPE_CHECKING imports:
application/cli → evaluation → application → adapters → ports →
domain → shared.
tests/unit/test_layering.py enforces this and the rules below (its
allowlist of exceptions is empty; keep it so).
- Root facade (
unified_kg_rag/__init__.py): the public API. It lazily re-exports the names users and extenders import (from unified_kg_rag import GraphRAGChain, Providers, ...); everything else is internal. Adding or removing a name means editingtests/unit/test_public_api.py(and a CHANGELOG "Breaking" entry for a removal or rename). Inside the package, import from it only__version__. domain/: technology-agnostic core —models/(Pydantic; the methodology catalogue inmethodology.py), pure algorithms (ingestion/merge/delta/resolve/analyze, community clustering (community_clustering), the methodology → stage map (methodologies), stage cache keys, document identity, visualization data and layout;retrieval/store names, index prefixes, hybrid normalization, PPR, abstention), andprompts/templates. Imports onlyshared: no port or adapter, not even for typing — domain code that reads a store declares the subset it needs as its ownProtocol(delta_detector.DocStatusReader, pinned toDocStatusPortbytests/unit/test_fake_port_signatures.py). No boto3/LangChain/backend imports, direct or transitive (tests/unit/test_domain_purity.pyimports every domain module in a clean interpreter and checkssys.modules).ports/: the interfaces the application wires and the adapters implement, written in terms of the domain models —DocStatusPort,ContentGuardPort,ModelFactoryPort(+LLMFactoryPort/EmbeddingFactoryPort/RerankFactoryPort)/TokenCounterPort(Protocols) and the write-side indexer ABCsBaseIndexer/GraphIndexer/VectorIndexer(+IndexingStats).ports/__init__is the port catalog. The retrieval/evaluation abstract bases are adapter bases (they construct infra in__init__):ports/__init__names them but does not export them; import them fromadapters.retrieval.base/adapters.evaluators.base.adapters/: concrete technology bindings. Rule: vendor packages hold clients/engines/model factories/caches, role packages hold port impls (a role package may import a vendor one, not the reverse; of the adapters a vendor package imports only the other vendor and the vendor-neutral kernelllm/+observability/, which import no other adapter package). Vendor:aws/(Bedrock, Neptune/OpenSearch clients, S3),local/(Ollama/OpenAI-compatible, graph storesqlite_graph.py, vector enginesearch_engine/). Role:storage/(indexers, incl.sqlite_graph_indexer.py),retrievers/,doc_status/(DynamoDB/SQLiteDocStatusPortimpls),guardrail/(BedrockContentGuardPortimpl). Alsollm/(provider-neutral chain assembly, retry, token estimate, the LangChain batch/XML helpers inllm/langchain.py),search_strategies/,retrieval/(bases + strategy registry + hybrid scorer + token/memory managers),ingestion/(LLM/IO-coupled chunker/extractor/loader/parser/ translator/document converter),renderers/,evaluators/(incl. the evaluator bases).application/: orchestration —ingestion/(pipeline + stages, stage cache and resume managers,resume,pipeline_metrics),storage/indexing_manager(withcross_run_merge,removal,reannotation,stored_items),retrieval/rag_chain(withquery_processing,filter_validation),prompts/,config.py(get_config), and the composition rootbootstrap.py. Onlybootstrap.pyandcli/(the entry points; pyproject scripts resolve tounified_kg_rag.application.cli.*) import vendor bindings or port implementations; everything else receives them (Providers,build_query_guard,build_checkpoint_sync).shared/: leaf kernel — logging, exceptions, metrics, observability hooks, write fence, pureutils/. It imports no other layer, so anything that needs domain models belongs in another layer;setup_loggingtakes the config structurally. Keepshared/__init__andshared/utils/__init__dependency-light (the domain imports them).evaluation/: a real logic package and its own layer (evaluators + manager, driven by the CLIs). Of the application it imports onlyapplication.retrievalandapplication.bootstrap, reaches the stores only through the chain (GraphRAGChain.check_filter_*) and imports no store adapter. TheragasLLM judge needs theevalextra (assertionneeds none).- Registries over hardcoded dispatch: search strategies register via
@register_strategy(adapters/retrieval/strategy_registry.py). Follow this pattern — andParserFactory.register_loader/@register_renderer— instead ofif/elifdispatch, and outside a plugin package import only its root (renderers and evaluators: also theirbasemodule; schema and seed sources and search strategies: the root only, the strategy registry beingadapters/retrieval/strategy_registry.py);_PLUGINSintests/unit/test_layering.pyis the list.EvaluationManager._resolve_evaluator_classis the one explicit type → class map (a new evaluator adds a branch there).
See docs/design.md §2 for the full layer map and dependency rule.
Adding things
Recipes for new strategies, backends, evaluators, renderers, parsers and
config sections live in one place: docs/design.md §15 "Extension Guide"
(read it before extending; update it, not this file, when a recipe changes).
The rules to keep in mind:
- Extend through the registries and the one evaluator type map, never new
if/elifdispatch. - Inject backends through constructors (
Providers,vector_indexer=/graph_indexer=,retriever_builders=,doc_status=); never hardcode a backend into a manager's__init__. - A config field change means a user-facing
Field(description=...)anduv run python scripts/gen_config_reference.py(regeneratesdocs/reference/configuration.md;tests/unit/test_config_reference.pychecks it).
Capabilities & CLIs
- Four retrieval methodologies (
Methodology; strategy per query viaRAGInput.search_strategy,autoroutes): GraphRAG community-summary (drift/global/local/simple), LightRAG dual-level keyword (mix/hybrid/naive), HippoRAG 2 Personalized PageRank (ppr;localranks its text units by it by default) and RAPTOR summary tree (tree, opt-in);iterativewrapsmixorlocalwith follow-up rounds. They share ingestion, indexing, caching, multilingual and hybrid-scoring infrastructure; only the retrieval algorithm differs. Every strategy class declares itsmethodology;indexing.methodologiesselects what ingestion builds (the stages follow), the build record names what a namespace holds, and a strategy reading what it does not hold is refused before any model call (docs/design.md§4.6, §6). - Incremental indexing: enable the doc-status registry
(
providers.doc_status.enabled; DynamoDB, or SQLite in local mode) to diff a corpus by content hash and only (re)index new/changed documents, merging into the live graph (IncrementalIndexer,ingestion/merge/, idempotentupsert_*/delete_by_idon both indexers). The registry lists each document's text units; a deletion asks the stores what cites them and removes only what no surviving text unit still states. - CLIs (
pyprojectscripts):run-ingestion,run-rag,run-eval,run-visualization(render from exported graph data, no ingestion),run-prompt-tuning(profile a corpus → domain-adaptedcustom_promptsYAML),prepare-benchmark(musique: corpus +run-evaldataset, downloaded at run time, never committed;assertions: questions and assertions from your corpus;structural: graph-structure questions),run-describe(a namespace's methodologies, strategies and counts; graph export),run-mcp-server(one namespace as read-only MCP tools for agents,application/cli/mcp_*.py),run-console(the local web console,application/cli/console/).run-eval --search-strategy a,b --repeats Nruns a paired comparison (evaluation/comparison.py, optional--pairwise-judge).docs/reference/cli.mdlists every flag; it is generated from the parsers byscripts/gen_cli_reference.py, so change a flag'shelp=and regenerate (a unit test fails when it is stale). - Evaluation: three LLM-free evaluators (the defaults;
run-eval --evaluatorspicks per run) plusragasandassertion(opt-in LLM judges):graph_aware(entity/relationship coverage = recall, from ground-truthexpected_entities/expected_relationships; precision/F1 intentionally not emitted — see the evaluator docstring),retrieval(hit@k/recall@k/MRR againstreference_sources) andanswer_match(exact match/token F1 againstanswer+metadata.answer_aliases). - Visualization: ingestion only exports
visualization_data.json(graph.visualization.export_data);run-visualizationrenders it through the renderers registered via@register_renderer(adapters/renderers/, one registry +RenderContext). The interactive renderer needs thevizextra; the static charts need none. - Extras:
eval(the ragas judge) andviz(pyvis) are optional, likeotel,ontology(rdflib),mcp(the MCP SDK ofrun-mcp-server),console(FastAPI and Uvicorn ofrun-console),local,cross-encoder(the local reranker),docxandunstructured; a feature whose extra is missing fails fast with aConfigurationErrornaming the extra. Tests that need one usetests/fixtures/extras.py; the CIcore-installjob runs without them. - Docs: user docs start at
docs/index.md(the hub), with task pages indocs/guides/, concepts and measured evidence indocs/concepts/, and reference indocs/reference/, including the generatedcli.mdandconfiguration.md. Operator procedures are indocs/operations.md, extension recipes indocs/design.md§15. Where content goes, the Korean (Tier-1) pages and the docs checker (uv run python scripts/check_docs.py): CONTRIBUTING.md Documentation.
Code standards
- Types: modern built-ins (
list,dict,X | None); no legacytyping.List. - Models: Pydantic at all boundaries (not dataclasses, except frozen config records).
- Files:
pathlib, notos.path. - Packages:
uv(uv sync, which includes the dev group), not pip. - Logging:
%-formatting, not f-strings —logger.info("did %s", x). - LLM calls: LangChain LCEL (
prompt | llm | parser); prompts live inunified_kg_rag/domain/prompts/*.pyfor version control, overridable viacustom_promptsconfig. - Exceptions: specific custom types from
shared/exceptions.py; fail fast at boundaries; degrade gracefully only where recovery is meaningful.
No customer data (MANDATORY)
This is a public repository. Customer-identifying or customer-confidential content MUST NEVER appear in application code, tests, evaluation datasets, fixtures, prompts, comments, docs, diagrams, or commit messages. This includes: customer/project names and codenames (e.g. internal engagement names), real contract figures/clauses, document filenames from a customer corpus, account ids, endpoints, and internal hostnames.
- Tests/fixtures/eval: use neutral synthetic data (generic entities like "Vendor"/"Buyer", made-up amounts). Never paste real customer text.
- Real-corpus tests: keep non-public corpora out of the repo entirely; the
gitignored
.test-corpus-backup/is for local copies only. - Before committing: grep the staged diff for customer terms.
Testing
Layout: tests/{unit,integration,property,fixtures/fakes}/. Markers: unit,
integration, property, aws (real AWS — skipped in CI), slow, perf
(timing assertions — weekly job only), weekly (heavy fidelity cases against
the original libraries — the weekly fidelity workflow; pull requests run a
sample).
- Tests run AWS-free by default. Use the port-based in-memory fakes in
tests/fixtures/fakes/(e.g.FakeDocStatusStore) instead of mocking boto3 ad hoc; usemotowhen an adapter must be exercised against a boto3 surface.tests/unit/test_fake_port_signatures.pyfails if a fake's method signatures drift from the port's. - Each test times out after 120 s (
pytest-timeout; override with@pytest.mark.timeout(n)). tests/integration/test_local_stores.pyneedsLOCAL_STORES=1and thedocker/compose.local.yamlstores; the CIlocal-storesjob runs it.tests/integration/test_embedded_e2e.pyrunsbackend: localend to end on the embedded SQLite stores (no containers, no AWS) in the default jobs.pytest-asynciois inasyncio_mode = "auto"—async def test_*just works.- Property tests (
hypothesis) cover invariants: merge laws, incremental rounds and interrupted runs converging with a full build, fusion monotonicity; theDocStatusPort.diffpartition runs against every registry intests/integration/test_doc_status_conformance.py. - Coverage gate ratchets up with measured coverage (the
--cov-fail-underfloor inquality.ymlsits just under it: currently 95, measured ~96%). Run:uv run --extra otel --extra eval --extra viz --extra ontology pytest -m "not aws and not perf and not weekly" -n logical --cov=unified_kg_rag.
Quality gate
CI (.github/workflows/quality.yml) runs ruff, black, isort, mypy, and
pytest+coverage; .pre-commit-config.yaml runs the linters and mypy, not
pytest or coverage. Install hooks with pre-commit install.
Git & collaboration workflow
Treat main as protected shared history. These rules apply to human
contributors and to Claude Code working in this repo.
- Never commit or push directly to
main. Do all work on a topic branch (feat/…,fix/…,docs/…,chore/…) and land it through a Pull Request, even for solo work — the PR is the review checkpoint and the audit trail. - One logical change per PR/commit. Keep them small and focused; don't mix a refactor, a feature, and a doc fix in one commit.
- Conventional Commits for every message:
type(scope): summaryin the imperative mood, ≤72-char subject. Types:feat,fix,docs,refactor,test,chore,style,perf,ci,build. Body explains why, not what the diff already shows. - Green before you push. Run
uv run pytest(its addopts deselectaws,perfandweekly) and the pre-commit hooks (ruff/black/isort/mypy) locally; never push a commit that fails the CI quality gate. Fix formatting before committing, not in a follow-up. - No force-push to
main, no history rewrites: they break every clone, fork, and open PR. - Never merge your own PR without review when a second maintainer is
available; for genuinely solo changes, still open the PR, let CI pass, and use
a squash-merge so
mainkeeps one clean commit per change. - Ask before side-effecting actions — pushing, opening/merging PRs, tagging releases, and any AWS resource creation or real-AWS tests. Approval for one action is not standing approval for the next.
- Customer-data check is a hard blocker. Before every commit, grep the staged diff for customer terms (see No customer data above); never commit or push a change that contains any.
Notes
- This file holds project conventions for Claude Code and contributors.
references/is gitignored: a place for local copies of the upstream GraphRAG and LightRAG sources used as porting reference, not part of this package.- Ask before side-effecting AWS actions (resource creation, real-AWS tests).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

