grag-mcp 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. grag_mcp-0.2.0/.dockerignore +19 -0
  2. grag_mcp-0.2.0/.editorconfig +21 -0
  3. grag_mcp-0.2.0/.env.example +26 -0
  4. grag_mcp-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +56 -0
  5. grag_mcp-0.2.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  6. grag_mcp-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  7. grag_mcp-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +30 -0
  8. grag_mcp-0.2.0/.github/copilot-instructions.md +105 -0
  9. grag_mcp-0.2.0/.github/dependabot.yml +20 -0
  10. grag_mcp-0.2.0/.github/prompts/add-a-parser.prompt.md +31 -0
  11. grag_mcp-0.2.0/.github/prompts/configure-dev-environment.prompt.md +21 -0
  12. grag_mcp-0.2.0/.github/prompts/cut-a-release.prompt.md +31 -0
  13. grag_mcp-0.2.0/.github/prompts/deploy-with-compose.prompt.md +28 -0
  14. grag_mcp-0.2.0/.github/prompts/run-locally.prompt.md +33 -0
  15. grag_mcp-0.2.0/.github/release.yml +31 -0
  16. grag_mcp-0.2.0/.github/workflows/ci.yml +138 -0
  17. grag_mcp-0.2.0/.github/workflows/copilot-setup-steps.yml +67 -0
  18. grag_mcp-0.2.0/.github/workflows/release.yml +140 -0
  19. grag_mcp-0.2.0/.gitignore +46 -0
  20. grag_mcp-0.2.0/.mcp.json +8 -0
  21. grag_mcp-0.2.0/.python-version +1 -0
  22. grag_mcp-0.2.0/AGENTS.md +246 -0
  23. grag_mcp-0.2.0/CHANGELOG.md +131 -0
  24. grag_mcp-0.2.0/CODE_OF_CONDUCT.md +61 -0
  25. grag_mcp-0.2.0/CONTRIBUTING.md +147 -0
  26. grag_mcp-0.2.0/Dockerfile +96 -0
  27. grag_mcp-0.2.0/LICENSE +201 -0
  28. grag_mcp-0.2.0/Makefile +46 -0
  29. grag_mcp-0.2.0/NOTICE +16 -0
  30. grag_mcp-0.2.0/PKG-INFO +281 -0
  31. grag_mcp-0.2.0/README.md +242 -0
  32. grag_mcp-0.2.0/SECURITY.md +50 -0
  33. grag_mcp-0.2.0/docker-compose.yml +76 -0
  34. grag_mcp-0.2.0/docs/ARCHITECTURE.md +147 -0
  35. grag_mcp-0.2.0/docs/ROADMAP.md +31 -0
  36. grag_mcp-0.2.0/docs/operations.md +253 -0
  37. grag_mcp-0.2.0/examples/README.md +21 -0
  38. grag_mcp-0.2.0/examples/checkov-policies/rds_encryption.yaml +22 -0
  39. grag_mcp-0.2.0/examples/checkov-policies/rds_public_access.yaml +15 -0
  40. grag_mcp-0.2.0/examples/checkov-policies/s3_versioning.yaml +15 -0
  41. grag_mcp-0.2.0/graph-rag.code-workspace +8 -0
  42. grag_mcp-0.2.0/pyproject.toml +99 -0
  43. grag_mcp-0.2.0/scripts/fetch_model.py +43 -0
  44. grag_mcp-0.2.0/src/graph_rag/__init__.py +0 -0
  45. grag_mcp-0.2.0/src/graph_rag/cli.py +246 -0
  46. grag_mcp-0.2.0/src/graph_rag/eval/__init__.py +5 -0
  47. grag_mcp-0.2.0/src/graph_rag/eval/corpus/deployment.md +47 -0
  48. grag_mcp-0.2.0/src/graph_rag/eval/corpus/policies.yaml +51 -0
  49. grag_mcp-0.2.0/src/graph_rag/eval/corpus/scheduler.py +75 -0
  50. grag_mcp-0.2.0/src/graph_rag/eval/corpus/task_queue.md +42 -0
  51. grag_mcp-0.2.0/src/graph_rag/eval/eval_case.py +44 -0
  52. grag_mcp-0.2.0/src/graph_rag/eval/eval_case_result.py +11 -0
  53. grag_mcp-0.2.0/src/graph_rag/eval/retrieval_eval_set.yaml +72 -0
  54. grag_mcp-0.2.0/src/graph_rag/eval/retrieval_evaluator.py +64 -0
  55. grag_mcp-0.2.0/src/graph_rag/graph/__init__.py +4 -0
  56. grag_mcp-0.2.0/src/graph_rag/graph/centrality_analyzer.py +59 -0
  57. grag_mcp-0.2.0/src/graph_rag/graph/client.py +28 -0
  58. grag_mcp-0.2.0/src/graph_rag/graph/graph_writer.py +289 -0
  59. grag_mcp-0.2.0/src/graph_rag/graph/schema.py +112 -0
  60. grag_mcp-0.2.0/src/graph_rag/http_app.py +30 -0
  61. grag_mcp-0.2.0/src/graph_rag/ingest/__init__.py +26 -0
  62. grag_mcp-0.2.0/src/graph_rag/ingest/chunker.py +57 -0
  63. grag_mcp-0.2.0/src/graph_rag/ingest/embedders/__init__.py +4 -0
  64. grag_mcp-0.2.0/src/graph_rag/ingest/embedders/embedder.py +10 -0
  65. grag_mcp-0.2.0/src/graph_rag/ingest/embedders/sentence_transformer_embedder.py +47 -0
  66. grag_mcp-0.2.0/src/graph_rag/ingest/enricher.py +31 -0
  67. grag_mcp-0.2.0/src/graph_rag/ingest/models/__init__.py +8 -0
  68. grag_mcp-0.2.0/src/graph_rag/ingest/models/chunk.py +15 -0
  69. grag_mcp-0.2.0/src/graph_rag/ingest/models/code_entity.py +21 -0
  70. grag_mcp-0.2.0/src/graph_rag/ingest/models/parsed_document.py +20 -0
  71. grag_mcp-0.2.0/src/graph_rag/ingest/models/policy_rule.py +16 -0
  72. grag_mcp-0.2.0/src/graph_rag/ingest/models/section.py +14 -0
  73. grag_mcp-0.2.0/src/graph_rag/ingest/models/source.py +13 -0
  74. grag_mcp-0.2.0/src/graph_rag/ingest/parser.py +12 -0
  75. grag_mcp-0.2.0/src/graph_rag/ingest/parser_registry.py +26 -0
  76. grag_mcp-0.2.0/src/graph_rag/ingest/parsers/__init__.py +6 -0
  77. grag_mcp-0.2.0/src/graph_rag/ingest/parsers/markdown_parser.py +147 -0
  78. grag_mcp-0.2.0/src/graph_rag/ingest/parsers/pdf_parser.py +297 -0
  79. grag_mcp-0.2.0/src/graph_rag/ingest/parsers/python_parser.py +301 -0
  80. grag_mcp-0.2.0/src/graph_rag/ingest/parsers/yaml_parser.py +179 -0
  81. grag_mcp-0.2.0/src/graph_rag/ingest_http_endpoint.py +26 -0
  82. grag_mcp-0.2.0/src/graph_rag/ingest_request.py +8 -0
  83. grag_mcp-0.2.0/src/graph_rag/ingestion_pipeline.py +85 -0
  84. grag_mcp-0.2.0/src/graph_rag/ingestion_result.py +20 -0
  85. grag_mcp-0.2.0/src/graph_rag/ingestion_watch_handler.py +46 -0
  86. grag_mcp-0.2.0/src/graph_rag/ingestion_watcher.py +40 -0
  87. grag_mcp-0.2.0/src/graph_rag/mcp_server/__init__.py +12 -0
  88. grag_mcp-0.2.0/src/graph_rag/mcp_server/bearer_token_middleware.py +26 -0
  89. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/__init__.py +21 -0
  90. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/code_centrality_result.py +14 -0
  91. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/code_search_result.py +15 -0
  92. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/neighbor_result.py +11 -0
  93. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/outline_node.py +9 -0
  94. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/policy_result.py +15 -0
  95. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/search_result.py +14 -0
  96. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/section_detail.py +16 -0
  97. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/section_outline_entry.py +8 -0
  98. grag_mcp-0.2.0/src/graph_rag/mcp_server/models/source_info.py +12 -0
  99. grag_mcp-0.2.0/src/graph_rag/mcp_server/retriever.py +505 -0
  100. grag_mcp-0.2.0/src/graph_rag/mcp_server/server.py +175 -0
  101. grag_mcp-0.2.0/src/graph_rag/memory/__init__.py +15 -0
  102. grag_mcp-0.2.0/src/graph_rag/memory/agent_memory.py +22 -0
  103. grag_mcp-0.2.0/src/graph_rag/memory/agent_memory_result.py +14 -0
  104. grag_mcp-0.2.0/src/graph_rag/memory/memory_pruner.py +73 -0
  105. grag_mcp-0.2.0/src/graph_rag/memory/memory_recaller.py +112 -0
  106. grag_mcp-0.2.0/src/graph_rag/memory/memory_writer.py +85 -0
  107. grag_mcp-0.2.0/src/graph_rag/memory/prune_result.py +8 -0
  108. grag_mcp-0.2.0/src/graph_rag/py.typed +0 -0
  109. grag_mcp-0.2.0/src/graph_rag/settings.py +20 -0
  110. grag_mcp-0.2.0/src/graph_rag/unsupported_file_type_error.py +8 -0
  111. grag_mcp-0.2.0/tests/__init__.py +0 -0
  112. grag_mcp-0.2.0/tests/test_chunker.py +43 -0
  113. grag_mcp-0.2.0/tests/test_cli_serve_mcp.py +77 -0
  114. grag_mcp-0.2.0/tests/test_http_app.py +58 -0
  115. grag_mcp-0.2.0/tests/test_ingest_http_endpoint.py +71 -0
  116. grag_mcp-0.2.0/tests/test_ingestion_pipeline.py +135 -0
  117. grag_mcp-0.2.0/tests/test_ingestion_watch_handler.py +78 -0
  118. grag_mcp-0.2.0/tests/test_markdown_parser.py +90 -0
  119. grag_mcp-0.2.0/tests/test_memory_pruner.py +34 -0
  120. grag_mcp-0.2.0/tests/test_memory_recaller.py +25 -0
  121. grag_mcp-0.2.0/tests/test_parser_registry.py +24 -0
  122. grag_mcp-0.2.0/tests/test_pdf_parser.py +218 -0
  123. grag_mcp-0.2.0/tests/test_python_parser.py +166 -0
  124. grag_mcp-0.2.0/tests/test_retrieval_evaluator.py +184 -0
  125. grag_mcp-0.2.0/tests/test_retriever.py +132 -0
  126. grag_mcp-0.2.0/tests/test_schema.py +52 -0
  127. grag_mcp-0.2.0/tests/test_sentence_transformer_embedder.py +38 -0
  128. grag_mcp-0.2.0/tests/test_settings.py +7 -0
  129. grag_mcp-0.2.0/tests/test_yaml_parser.py +160 -0
  130. grag_mcp-0.2.0/uv.lock +1674 -0
@@ -0,0 +1,19 @@
1
+ .venv
2
+ .git
3
+ .github
4
+ .pytest_cache
5
+ .ruff_cache
6
+ .mypy_cache
7
+ __pycache__
8
+ *.pyc
9
+ .env
10
+ models
11
+ tests
12
+ examples
13
+ scripts
14
+ # ...except the model-fetch script, which the builder stage runs to vendor the
15
+ # embedding model into the image.
16
+ !scripts/fetch_model.py
17
+ training-docs
18
+ docs
19
+ .claude
@@ -0,0 +1,21 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+
10
+ [*.py]
11
+ indent_size = 4
12
+ max_line_length = 100
13
+
14
+ [*.{yml,yaml,json,toml}]
15
+ indent_size = 2
16
+
17
+ [*.md]
18
+ trim_trailing_whitespace = false
19
+
20
+ [Makefile]
21
+ indent_style = tab
@@ -0,0 +1,26 @@
1
+ # Copy to .env and adjust for local dev. Never commit the real .env.
2
+
3
+ NEO4J_USER=neo4j
4
+ NEO4J_PASSWORD=changeme-local-dev
5
+ NEO4J_URI=bolt://localhost:7687
6
+
7
+ # MCP server
8
+ MCP_HOST=127.0.0.1
9
+ MCP_PORT=8765
10
+ MCP_AUTH_TOKEN=
11
+
12
+ # Base images for `docker compose`. Override in restricted environments that
13
+ # only allow approved hardened images. Defaults match what CI builds/scans.
14
+ # See docs/operations.md "Restricted / hardened-registry environments".
15
+ #
16
+ # Docker Hardened Images (needs `docker login dhi.io`; Select/Enterprise
17
+ # subscribers swap `dhi.io/` for `<your-org>/`). DHI's Neo4j is Community
18
+ # edition on the same CalVer stream as the official image, but has no
19
+ # wget/curl or awk — set NEO4J_PLUGINS= and preload the apoc/gds jars into
20
+ # the neo4j_plugins volume. BUILDER is a throwaway stage (-dev = has a
21
+ # shell); RUNTIME's own Python is unused. See docs/operations.md.
22
+ # NEO4J_IMAGE=dhi.io/neo4j:2026
23
+ # NEO4J_PLUGINS=
24
+ # BUILDER_IMAGE=dhi.io/python:3-dev
25
+ # RUNTIME_IMAGE=dhi.io/python:3
26
+ # UV_IMAGE=<registry>/uv:0.12.5
@@ -0,0 +1,56 @@
1
+ name: Bug report
2
+ description: Something isn't working as documented
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for the report. Please search existing issues first.
9
+ - type: textarea
10
+ id: what-happened
11
+ attributes:
12
+ label: What happened
13
+ description: What you expected vs. what actually occurred.
14
+ validations:
15
+ required: true
16
+ - type: textarea
17
+ id: repro
18
+ attributes:
19
+ label: Steps to reproduce
20
+ description: Exact commands / MCP calls / inputs. A minimal repro helps a lot.
21
+ placeholder: |
22
+ 1. make up && make apply-schema
23
+ 2. uv run grag-mcp ingest ...
24
+ 3. ...
25
+ validations:
26
+ required: true
27
+ - type: textarea
28
+ id: logs
29
+ attributes:
30
+ label: Logs / traceback
31
+ render: shell
32
+ - type: input
33
+ id: version
34
+ attributes:
35
+ label: Version / commit
36
+ description: Output of `git rev-parse --short HEAD` or the release tag.
37
+ validations:
38
+ required: true
39
+ - type: dropdown
40
+ id: run-mode
41
+ attributes:
42
+ label: How are you running it?
43
+ options:
44
+ - CLI (uv run grag-mcp ...)
45
+ - MCP server (make mcp-serve)
46
+ - docker compose
47
+ - Other / not sure
48
+ validations:
49
+ required: true
50
+ - type: input
51
+ id: env
52
+ attributes:
53
+ label: OS, Python, Neo4j image
54
+ placeholder: "macOS 15 / Python 3.12.4 / neo4j:2026.07.1"
55
+ validations:
56
+ required: true
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question / discussion
4
+ url: https://github.com/tmustafiz/graph-rag/discussions
5
+ about: Ask usage questions or propose ideas before opening an issue.
6
+ - name: Security vulnerability
7
+ url: https://github.com/tmustafiz/graph-rag/security/advisories/new
8
+ about: Report privately. Do not open a public issue for security problems.
@@ -0,0 +1,44 @@
1
+ name: Feature request
2
+ description: Suggest a new capability or improvement
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem / motivation
9
+ description: What are you trying to do that's hard or impossible today?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed solution
16
+ description: What should happen? Sketch the CLI flag / MCP tool / config if you can.
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: Alternatives considered
23
+ - type: dropdown
24
+ id: area
25
+ attributes:
26
+ label: Area
27
+ options:
28
+ - Ingestion / parsers
29
+ - Retrieval / ranking
30
+ - Graph schema / enrichment
31
+ - MCP tools
32
+ - Agent memory
33
+ - Embeddings backend
34
+ - Ops / deployment
35
+ - Docs
36
+ - Other
37
+ validations:
38
+ required: true
39
+ - type: checkboxes
40
+ id: contribute
41
+ attributes:
42
+ label: Contribution
43
+ options:
44
+ - label: I'm willing to open a PR for this
@@ -0,0 +1,30 @@
1
+ <!-- Thanks for contributing! Keep PRs focused; open an issue first for anything non-trivial. -->
2
+
3
+ ## Summary
4
+
5
+ <!-- What does this change and why? -->
6
+
7
+ ## Related issue
8
+
9
+ Closes #
10
+
11
+ ## Changes
12
+
13
+ -
14
+
15
+ ## Verification
16
+
17
+ ```
18
+ # paste the commands you ran and their results
19
+ uv run ruff check .
20
+ uv run ruff format --check .
21
+ uv run pytest -q
22
+ ```
23
+
24
+ ## Checklist
25
+
26
+ - [ ] Lint, format, and tests pass locally
27
+ - [ ] Tests added/updated for the change
28
+ - [ ] `CHANGELOG.md` updated under `[Unreleased]`
29
+ - [ ] Follows the one-class-per-file convention (see `CONTRIBUTING.md`)
30
+ - [ ] Docs updated (README / `docs/`) if behavior or interfaces changed
@@ -0,0 +1,105 @@
1
+ # GitHub Copilot instructions — graph-rag
2
+
3
+ These rules are prepended to every Copilot request in this repo. The full
4
+ reference is [`AGENTS.md`](../AGENTS.md); this file is the short version.
5
+
6
+ ## What this project is
7
+
8
+ A local-first **Graph RAG knowledge base for coding agents**. It ingests
9
+ PDF / Markdown / Python / YAML(Checkov) into a **Neo4j** knowledge graph and
10
+ serves hybrid retrieval + the agent's own working memory over an **MCP** server
11
+ (Streamable HTTP, default `http://127.0.0.1:8765/mcp`). Runs entirely locally;
12
+ the embedding model is local.
13
+
14
+ ## Names — do not mix these up
15
+
16
+ | Thing | Value |
17
+ | --- | --- |
18
+ | PyPI distribution + CLI command | `grag-mcp` |
19
+ | Python import package + `src/` dir | `graph_rag` |
20
+ | GitHub repo | `graph-rag` |
21
+ | MCP server identity (`MCPServer(name=…)`, `graph-rag://sources`) | `graph-rag` — never rename |
22
+
23
+ CLI is invoked as `uv run grag-mcp <verb>` (or `grag-mcp <verb>` once installed).
24
+ Verbs: `status`, `apply-schema`, `ingest`, `serve-mcp` (`--stdio` for stdio
25
+ transport), `compute-centrality`, `prune-memory`, `eval-retrieval`.
26
+
27
+ ## How to work
28
+
29
+ - **Think first.** State assumptions. If the request has multiple reasonable
30
+ readings, present them — don't silently pick one.
31
+ - **Simplest thing that works.** No speculative abstractions, no unrequested
32
+ features. If 200 lines could be 50, write 50.
33
+ - **Surgical diffs.** Touch only what the task needs. Don't reformat or refactor
34
+ adjacent code. Remove only dead code your change created.
35
+ - **No false completion.** Complete, runnable code — never stubs or `TODO`.
36
+ Never say "done" without running the verification below. If blocked, say so
37
+ and give the exact command to check.
38
+
39
+ ## Python standards
40
+
41
+ - Python 3.12+, full type hints, Pydantic v2 for data crossing a boundary.
42
+ - `ruff` for lint + format (`line-length = 100`, rules `E,F,I,UP,B`).
43
+ - `pathlib.Path`, not `os.path`. Specific exception types, not bare `except`.
44
+ - Dependency injection over module-level globals/singletons.
45
+ - Avoid single-letter names.
46
+
47
+ ## One class per file (strict)
48
+
49
+ - Every primary class in its own `lower_snake_case.py`; filename is the class
50
+ name in snake_case (`ParserRegistry` → `parser_registry.py`). Small helper
51
+ dataclasses/enums used only by that class may sit alongside it.
52
+ - Every package has an `__init__.py` that re-exports its public classes
53
+ (`from .parser_registry import ParserRegistry`) and defines `__all__`.
54
+ - Consumers import from the package (`from graph_rag.ingest import ParserRegistry`),
55
+ never the submodule. Within a package use relative imports (`from .x import X`).
56
+ - A new file type = a new self-contained parser class registered in the registry.
57
+ Never a rewrite of the pipeline.
58
+
59
+ ## Verification — run before handing back
60
+
61
+ ```bash
62
+ make lint # uv run ruff check .
63
+ uv run ruff format --check .
64
+ make test # uv run pytest
65
+ make eval # ONLY if you touched chunking / embedding / ranking (needs Neo4j)
66
+ ```
67
+
68
+ CI (`.github/workflows/ci.yml`) runs the first three on every PR, plus the
69
+ retrieval eval and a Trivy scan of the Docker image.
70
+
71
+ ## Planning & PRs
72
+
73
+ Planning lives on **GitHub**, not in the repo — Project board, milestones,
74
+ issues. Branch from `main`, open a PR that says `Closes #<n>`, and let the repo
75
+ owner merge and delete the branch. For a non-trivial task, post a `[CHECKPOINT]`
76
+ comment on the issue/PR before starting (objective / done & verified / critical
77
+ context / discarded paths / next step).
78
+
79
+ ## Don't break these
80
+
81
+ - **Never commit `.env`** (gitignored). Only `.env.example` is tracked; its
82
+ placeholder password is `changeme-local-dev`.
83
+ - The MCP server binds `127.0.0.1` only; origin / DNS-rebinding checks are
84
+ always on; `MCP_AUTH_TOKEN` (optional) adds a bearer check. Don't loosen these.
85
+ - `NEO4J_IMAGE`, `BUILDER_IMAGE`, `RUNTIME_IMAGE`, `UV_IMAGE` are overridable for
86
+ hardened-registry environments — keep the public defaults, keep them
87
+ overridable. See [`docs/operations.md`](../docs/operations.md).
88
+ - Neo4j needs the **APOC + GDS** plugins. The stock `neo4j` image auto-installs
89
+ them from `NEO4J_PLUGINS` in `docker-compose.yml`; hardened images need them
90
+ preloaded (see operations.md).
91
+ - The repo ships **no document corpus**. `examples/` holds a tiny Checkov sample
92
+ set — that's it.
93
+
94
+ ## Report back in this format
95
+
96
+ ```
97
+ **What changed**
98
+ - <file>: <what and why>
99
+
100
+ **Verification run**
101
+ - <command> → <result>
102
+
103
+ **Remaining issues / risks**
104
+ - <list or "None">
105
+ ```
@@ -0,0 +1,20 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "uv"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ groups:
8
+ python-minor-patch:
9
+ update-types: ["minor", "patch"]
10
+ open-pull-requests-limit: 5
11
+
12
+ - package-ecosystem: "github-actions"
13
+ directory: "/"
14
+ schedule:
15
+ interval: "weekly"
16
+
17
+ - package-ecosystem: "docker"
18
+ directory: "/"
19
+ schedule:
20
+ interval: "weekly"
@@ -0,0 +1,31 @@
1
+ ---
2
+ mode: agent
3
+ description: Add ingestion support for a new file type (a new parser class).
4
+ ---
5
+ Add a parser for a new file type: ${input:fileType:e.g. reStructuredText / .rst}.
6
+
7
+ This must be a small, isolated change — a new parser class registered in the
8
+ registry. Do **not** modify the chunker, pipeline, graph writer, or existing
9
+ parsers unless the new type genuinely requires it (say why if so).
10
+
11
+ 1. Read an existing parser to match the pattern — e.g.
12
+ `src/graph_rag/ingest/parsers/markdown_parser.py` (prose) or
13
+ `python_parser.py` (code). Note the return type (`ParsedDocument` / sections /
14
+ code entities) and how it's registered.
15
+ 2. Create `src/graph_rag/ingest/parsers/<snake_case>_parser.py` with one class,
16
+ `<PascalCase>Parser`, filename = class name in snake_case. One class per file.
17
+ 3. Register it: add it to the parser registry keyed by file extension, and
18
+ re-export it from the package `__init__.py` (`from .x_parser import XParser`,
19
+ add to `__all__`).
20
+ 4. Heavy or optionally-licensed third-party imports go **lazily inside the parse
21
+ method** with an actionable error if missing (see `pdf_parser.py`'s handling
22
+ of `pymupdf`) — never at module top. If it needs a new dependency, add it as
23
+ an optional extra in `pyproject.toml`, not a base dependency.
24
+ 5. Tests in `tests/test_<snake_case>_parser.py`: a normal parse, an empty file,
25
+ and the missing-dependency error path if step 4 applies.
26
+ 6. Verify: `make lint`, `uv run ruff format --check .`, `make test`. Run
27
+ `make eval` only if you touched chunking/embedding/ranking.
28
+ 7. Update `CHANGELOG.md` (`[Unreleased]`) and the file-type list in `README.md`
29
+ and `docs/ARCHITECTURE.md`.
30
+
31
+ Report in the What changed / Verification run / Remaining issues format.
@@ -0,0 +1,21 @@
1
+ ---
2
+ mode: agent
3
+ description: Set up a local graph-rag dev environment from a fresh clone.
4
+ ---
5
+ Get this repo running locally from a fresh clone.
6
+
7
+ Steps:
8
+ 1. `cp .env.example .env`. Leave `NEO4J_PASSWORD=changeme-local-dev` unless the
9
+ user asked to change it. Never commit `.env`.
10
+ 2. `make install` (`uv sync --all-extras`).
11
+ 3. `make fetch-model` — downloads `sentence-transformers/all-MiniLM-L6-v2` into
12
+ `models/all-MiniLM-L6-v2/` (~87 MB). Needs network once; after that
13
+ ingestion/tests can run with `HF_HUB_OFFLINE=1`.
14
+ 4. `make up` — starts Neo4j in Docker. The stock `neo4j` image auto-installs the
15
+ APOC + GDS plugins from `NEO4J_PLUGINS` in `docker-compose.yml`; nothing to
16
+ do. Wait until `make status` prints `Neo4j is reachable.`
17
+ 5. `make apply-schema` — constraints, full-text indexes, vector indexes.
18
+ 6. Verify: `make lint`, `make test`.
19
+
20
+ Report which steps ran and their output. If `make fetch-model` can't reach
21
+ `huggingface.co`, say so — ingestion will fail without the model.
@@ -0,0 +1,31 @@
1
+ ---
2
+ mode: agent
3
+ description: Prepare a grag-mcp release (version bump, changelog, tag).
4
+ ---
5
+ Prepare the ${input:version:e.g. 0.2.0} release of `grag-mcp`.
6
+
7
+ Publishing is automated: pushing a `vX.Y.Z` tag triggers
8
+ `.github/workflows/release.yml`, which builds and publishes to PyPI via Trusted
9
+ Publishing (no stored token). Your job is to prepare the commit and tag.
10
+
11
+ 1. Bump `version` in `pyproject.toml` to `${input:version}`.
12
+ 2. `CHANGELOG.md`: turn the `[Unreleased]` section into
13
+ `[${input:version}] - <today's date, YYYY-MM-DD>`, add a fresh empty
14
+ `[Unreleased]`, and update the link definitions at the bottom.
15
+ 3. Sanity-check the build:
16
+ ```bash
17
+ uv build
18
+ uvx twine check dist/*
19
+ test "$(uv version --short)" = "${input:version}"
20
+ ```
21
+ 4. Commit on a branch (`release/v${input:version}`), open a PR that says
22
+ `Closes #<n>` if there's a release issue. Do **not** merge or push the tag —
23
+ the repo owner does that after merge:
24
+ ```
25
+ git tag v${input:version} && git push origin v${input:version}
26
+ ```
27
+ 5. Note in the PR that the PyPI Trusted Publisher for project `grag-mcp` and the
28
+ `pypi` GitHub Environment must already exist (one-time setup, owner's task).
29
+
30
+ Do not rename the distribution, the import package, or the MCP server identity —
31
+ see `AGENTS.md` → "Names".
@@ -0,0 +1,28 @@
1
+ ---
2
+ mode: agent
3
+ description: Build and deploy the full stack (Neo4j + MCP server) with Docker Compose.
4
+ ---
5
+ Deploy the whole stack with Docker Compose.
6
+
7
+ 1. `docker compose build` — multi-stage: the app venv is built against a
8
+ standalone CPython (via `uv`) and copied into a distroless runtime image
9
+ (no shell, non-root uid 65532). Entry point is `/app/.venv/bin/grag-mcp`.
10
+ 2. `docker compose up -d` — starts `graph-rag-neo4j` then `graph-rag-mcp`
11
+ (the latter waits on the Neo4j healthcheck). Ports are published on
12
+ `127.0.0.1` only: `7474`/`7687` (Neo4j), `8765` (MCP).
13
+ 3. Verify:
14
+ - `docker compose ps` — both up, `graph-rag-neo4j` healthy.
15
+ - `docker compose exec -T mcp-server grag-mcp status` → `Neo4j is reachable.`
16
+ - `curl` the MCP `initialize` (see `run-locally.prompt.md`) → 200,
17
+ `"serverInfo":{"name":"graph-rag"}`.
18
+ - `docker compose logs mcp-server` → `MCP server listening on …:8765/mcp`.
19
+
20
+ Hardened / restricted registries: every base image is overridable via `.env`
21
+ (`NEO4J_IMAGE`, `BUILDER_IMAGE`, `RUNTIME_IMAGE`, `UV_IMAGE`). For Docker
22
+ Hardened Images the working set is `NEO4J_IMAGE=dhi.io/neo4j:2026` +
23
+ `NEO4J_PLUGINS=` (that image has no wget/awk, so preload APOC/GDS jars into the
24
+ `neo4j_plugins` volume), `BUILDER_IMAGE=dhi.io/python:3-dev`,
25
+ `RUNTIME_IMAGE=dhi.io/python:3`. Full recipe and constraints:
26
+ [`docs/operations.md`](../../docs/operations.md) → "Restricted / hardened-registry
27
+ environments". Keep the tracked defaults public and overridable — don't hardcode
28
+ a `dhi.io/...` image as the default.
@@ -0,0 +1,33 @@
1
+ ---
2
+ mode: agent
3
+ description: Run the MCP server locally and ingest content into the graph.
4
+ ---
5
+ Run graph-rag locally and load some content.
6
+
7
+ Assumes the dev environment is configured (see
8
+ `configure-dev-environment.prompt.md`) and Neo4j is up (`make up`,
9
+ `make status` → `Neo4j is reachable.`).
10
+
11
+ 1. Ingest content:
12
+ - `make ingest INGEST_PATH=examples/checkov-policies` for the bundled sample,
13
+ or `uv run grag-mcp ingest <path>` for a file or directory the user names.
14
+ - Re-running is cheap: unchanged files (by content hash) are skipped.
15
+ - `--dry-run` previews without writing; `--watch` re-ingests on change.
16
+ 2. (Optional) `uv run grag-mcp compute-centrality` — GDS PageRank over the
17
+ `CodeEntity` CALLS/IMPORTS graph; needed for `get_central_code_entities`.
18
+ Requires Python source to have been ingested first.
19
+ 3. Serve:
20
+ - HTTP (default): `make mcp-serve` → `http://127.0.0.1:8765/mcp`.
21
+ - stdio (for clients that spawn the server): `uv run grag-mcp serve-mcp --stdio`.
22
+ 4. Smoke-test the HTTP server:
23
+ ```bash
24
+ curl -s -X POST http://127.0.0.1:8765/mcp \
25
+ -H 'Content-Type: application/json' \
26
+ -H 'Accept: application/json, text/event-stream' \
27
+ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"c","version":"0"}}}'
28
+ ```
29
+ Expect HTTP 200 with `"serverInfo":{"name":"graph-rag"}`.
30
+
31
+ Do not change `MCP_HOST` to `0.0.0.0` on the host, and do not disable the
32
+ origin / DNS-rebinding checks. Set `MCP_AUTH_TOKEN` in `.env` if the user wants
33
+ a bearer-token gate.
@@ -0,0 +1,31 @@
1
+ # Configures GitHub's "Generate release notes" button and the notes attached to
2
+ # published releases. Categories are matched by PR label, top to bottom.
3
+ changelog:
4
+ exclude:
5
+ labels:
6
+ - duplicate
7
+ - invalid
8
+ - wontfix
9
+ authors:
10
+ - dependabot
11
+ categories:
12
+ - title: Features
13
+ labels:
14
+ - enhancement
15
+ - title: Fixes
16
+ labels:
17
+ - bug
18
+ - title: Build, CI & Ops
19
+ labels:
20
+ - "type: chore"
21
+ - "area: ops"
22
+ - title: Documentation
23
+ labels:
24
+ - documentation
25
+ - "area: docs"
26
+ - title: Dependencies
27
+ labels:
28
+ - dependencies
29
+ - title: Other changes
30
+ labels:
31
+ - "*"
@@ -0,0 +1,138 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+ schedule:
9
+ # Weekly, so a CVE disclosed against an otherwise-unchanged image still trips
10
+ # the `image` job (Mondays 07:00 UTC).
11
+ - cron: "0 7 * * 1"
12
+
13
+ concurrency:
14
+ group: ci-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ lint:
19
+ name: Lint & format
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v7
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v7
25
+ with:
26
+ enable-cache: true
27
+ - name: Sync dependencies
28
+ run: uv sync --all-extras --dev
29
+ - name: ruff check
30
+ run: uv run ruff check .
31
+ - name: ruff format --check
32
+ run: uv run ruff format --check .
33
+
34
+ test:
35
+ name: Tests (Python ${{ matrix.python-version }})
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ python-version: ["3.12", "3.13"]
41
+ steps:
42
+ - uses: actions/checkout@v7
43
+ - name: Install uv
44
+ uses: astral-sh/setup-uv@v7
45
+ with:
46
+ enable-cache: true
47
+ python-version: ${{ matrix.python-version }}
48
+ - name: Sync dependencies
49
+ run: uv sync --all-extras --dev
50
+ - name: Cache embedding model
51
+ id: model-cache
52
+ uses: actions/cache@v6
53
+ with:
54
+ path: models/all-MiniLM-L6-v2
55
+ key: minilm-l6-v2-v1
56
+ - name: Fetch embedding model
57
+ if: steps.model-cache.outputs.cache-hit != 'true'
58
+ run: make fetch-model
59
+ - name: Run pytest
60
+ # Model is on disk (fetched or restored from cache) — no network needed.
61
+ env:
62
+ HF_HUB_OFFLINE: "1"
63
+ run: uv run pytest -q
64
+
65
+ eval:
66
+ name: Retrieval eval
67
+ runs-on: ubuntu-latest
68
+ services:
69
+ neo4j:
70
+ image: neo4j:2026.07.1
71
+ env:
72
+ NEO4J_AUTH: neo4j/testpassword
73
+ ports:
74
+ - 7687:7687
75
+ - 7474:7474
76
+ options: >-
77
+ --health-cmd "wget -qO- http://localhost:7474 || exit 1"
78
+ --health-interval 10s --health-timeout 5s --health-retries 20
79
+ env:
80
+ NEO4J_URI: bolt://localhost:7687
81
+ NEO4J_USER: neo4j
82
+ NEO4J_PASSWORD: testpassword
83
+ HF_HUB_OFFLINE: "1"
84
+ steps:
85
+ - uses: actions/checkout@v7
86
+ - name: Install uv
87
+ uses: astral-sh/setup-uv@v7
88
+ with:
89
+ enable-cache: true
90
+ python-version: "3.12"
91
+ - name: Sync dependencies
92
+ run: uv sync --all-extras --dev
93
+ - name: Cache embedding model
94
+ id: model-cache
95
+ uses: actions/cache@v6
96
+ with:
97
+ path: models/all-MiniLM-L6-v2
98
+ key: minilm-l6-v2-v1
99
+ - name: Fetch embedding model
100
+ if: steps.model-cache.outputs.cache-hit != 'true'
101
+ run: make fetch-model
102
+ - name: Apply schema and run retrieval eval
103
+ run: |
104
+ uv run grag-mcp apply-schema
105
+ uv run grag-mcp eval-retrieval
106
+
107
+ image:
108
+ name: Image build & CVE scan
109
+ runs-on: ubuntu-latest
110
+ steps:
111
+ - uses: actions/checkout@v7
112
+
113
+ - name: Set up Docker Buildx
114
+ uses: docker/setup-buildx-action@v4
115
+
116
+ - name: Build runtime image
117
+ uses: docker/build-push-action@v7
118
+ with:
119
+ context: .
120
+ load: true
121
+ tags: graph-rag:ci
122
+ cache-from: type=gha
123
+ cache-to: type=gha,mode=max
124
+
125
+ - name: Trivy scan (fail on fixable HIGH/CRITICAL)
126
+ uses: aquasecurity/trivy-action@v0.36.0
127
+ # Pull the vuln DB from ECR, not GHCR, to dodge anonymous-pull rate limits.
128
+ env:
129
+ TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db
130
+ TRIVY_JAVA_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-java-db
131
+ with:
132
+ image-ref: graph-rag:ci
133
+ format: table
134
+ severity: HIGH,CRITICAL
135
+ # Only block on CVEs that actually have a fix — an unfixable base CVE
136
+ # shouldn't wedge every PR. Flip to false to tighten.
137
+ ignore-unfixed: true
138
+ exit-code: "1"