exactdocs 0.1.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 (56) hide show
  1. exactdocs-0.1.0/.gitignore +33 -0
  2. exactdocs-0.1.0/PKG-INFO +35 -0
  3. exactdocs-0.1.0/README.md +11 -0
  4. exactdocs-0.1.0/features/catalog.feature +20 -0
  5. exactdocs-0.1.0/features/search.feature +17 -0
  6. exactdocs-0.1.0/features/steps/http_steps.py +56 -0
  7. exactdocs-0.1.0/pyproject.toml +55 -0
  8. exactdocs-0.1.0/src/exactdocs/__init__.py +5 -0
  9. exactdocs-0.1.0/src/exactdocs/__main__.py +3 -0
  10. exactdocs-0.1.0/src/exactdocs/_version.py +6 -0
  11. exactdocs-0.1.0/src/exactdocs/_web/assets/index-B350HwjP.js +10 -0
  12. exactdocs-0.1.0/src/exactdocs/_web/assets/index-CG8rwfz9.css +2 -0
  13. exactdocs-0.1.0/src/exactdocs/_web/assets/routes-CCGZxbYl.js +1 -0
  14. exactdocs-0.1.0/src/exactdocs/_web/index.html +13 -0
  15. exactdocs-0.1.0/src/exactdocs/bootstrap/__init__.py +5 -0
  16. exactdocs-0.1.0/src/exactdocs/bootstrap/bridges.py +27 -0
  17. exactdocs-0.1.0/src/exactdocs/bootstrap/cli.py +48 -0
  18. exactdocs-0.1.0/src/exactdocs/bootstrap/container.py +28 -0
  19. exactdocs-0.1.0/src/exactdocs/bootstrap/http.py +90 -0
  20. exactdocs-0.1.0/src/exactdocs/bootstrap/mcp.py +21 -0
  21. exactdocs-0.1.0/src/exactdocs/bootstrap/settings.py +15 -0
  22. exactdocs-0.1.0/src/exactdocs/catalog/__init__.py +9 -0
  23. exactdocs-0.1.0/src/exactdocs/catalog/adapters/__init__.py +0 -0
  24. exactdocs-0.1.0/src/exactdocs/catalog/adapters/driven/__init__.py +0 -0
  25. exactdocs-0.1.0/src/exactdocs/catalog/adapters/driven/memory.py +35 -0
  26. exactdocs-0.1.0/src/exactdocs/catalog/adapters/driving/__init__.py +0 -0
  27. exactdocs-0.1.0/src/exactdocs/catalog/adapters/driving/http.py +21 -0
  28. exactdocs-0.1.0/src/exactdocs/catalog/adapters/driving/mcp.py +18 -0
  29. exactdocs-0.1.0/src/exactdocs/catalog/dtos.py +42 -0
  30. exactdocs-0.1.0/src/exactdocs/catalog/errors.py +16 -0
  31. exactdocs-0.1.0/src/exactdocs/catalog/models.py +34 -0
  32. exactdocs-0.1.0/src/exactdocs/catalog/module.py +27 -0
  33. exactdocs-0.1.0/src/exactdocs/catalog/ports/__init__.py +4 -0
  34. exactdocs-0.1.0/src/exactdocs/catalog/ports/driven.py +18 -0
  35. exactdocs-0.1.0/src/exactdocs/catalog/ports/driving.py +21 -0
  36. exactdocs-0.1.0/src/exactdocs/catalog/use_cases.py +33 -0
  37. exactdocs-0.1.0/src/exactdocs/py.typed +0 -0
  38. exactdocs-0.1.0/src/exactdocs/retrieval/__init__.py +8 -0
  39. exactdocs-0.1.0/src/exactdocs/retrieval/adapters/__init__.py +0 -0
  40. exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driven/__init__.py +0 -0
  41. exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driven/memory.py +26 -0
  42. exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driving/__init__.py +0 -0
  43. exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driving/http.py +17 -0
  44. exactdocs-0.1.0/src/exactdocs/retrieval/adapters/driving/mcp.py +28 -0
  45. exactdocs-0.1.0/src/exactdocs/retrieval/dtos.py +53 -0
  46. exactdocs-0.1.0/src/exactdocs/retrieval/errors.py +17 -0
  47. exactdocs-0.1.0/src/exactdocs/retrieval/models.py +34 -0
  48. exactdocs-0.1.0/src/exactdocs/retrieval/module.py +18 -0
  49. exactdocs-0.1.0/src/exactdocs/retrieval/ports/__init__.py +4 -0
  50. exactdocs-0.1.0/src/exactdocs/retrieval/ports/driven.py +26 -0
  51. exactdocs-0.1.0/src/exactdocs/retrieval/ports/driving.py +13 -0
  52. exactdocs-0.1.0/src/exactdocs/retrieval/use_cases.py +22 -0
  53. exactdocs-0.1.0/tests/architecture/test_architecture.py +171 -0
  54. exactdocs-0.1.0/tests/bootstrap/test_app.py +64 -0
  55. exactdocs-0.1.0/tests/catalog/test_use_cases.py +42 -0
  56. exactdocs-0.1.0/tests/retrieval/test_search_docs.py +54 -0
@@ -0,0 +1,33 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ coverage.xml
12
+ htmlcov/
13
+ reports/
14
+
15
+ # Built web UI bundled into the wheel / image (see web/README.md)
16
+ packages/exactdocs/src/exactdocs/_web/
17
+
18
+ # Local data and secrets
19
+ data/
20
+ *.db
21
+ .env
22
+ .env.*
23
+ !.env.example
24
+
25
+ # Editors / OS
26
+ .idea/
27
+ .vscode/*
28
+ !.vscode/extensions.json
29
+ .DS_Store
30
+ Thumbs.db
31
+
32
+ # Claude Code local settings
33
+ .claude/settings.local.json
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.5
2
+ Name: exactdocs
3
+ Version: 0.1.0
4
+ Summary: Self-hosted, version-accurate documentation for AI coding agents (MCP server).
5
+ Project-URL: Repository, https://github.com/SirCypkowskyy/ExactDocs
6
+ Project-URL: Issues, https://github.com/SirCypkowskyy/ExactDocs/issues
7
+ Author: Cyprian Gburek
8
+ License-Expression: Apache-2.0
9
+ Keywords: ai-agents,documentation,fastmcp,mcp,rag
10
+ Classifier: Development Status :: 2 - Pre-Alpha
11
+ Classifier: Framework :: FastAPI
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.14
15
+ Requires-Dist: cyclopts>=4
16
+ Requires-Dist: exactdocs-kernel==0.1.0
17
+ Requires-Dist: fastapi>=0.120
18
+ Requires-Dist: fastmcp>=4
19
+ Requires-Dist: mcp>=2
20
+ Requires-Dist: pydantic-settings>=2.11
21
+ Requires-Dist: pydantic>=2.12
22
+ Requires-Dist: uvicorn[standard]>=0.38
23
+ Description-Content-Type: text/markdown
24
+
25
+ # exactdocs
26
+
27
+ Self-hosted, version-accurate documentation for AI coding agents: an MCP server that serves
28
+ the right docs for the right library version, verbatim and with sources.
29
+
30
+ ```bash
31
+ uvx exactdocs serve # HTTP: web UI + MCP on http://localhost:3000
32
+ uvx exactdocs serve --stdio # MCP over stdio
33
+ ```
34
+
35
+ See the [project README](https://github.com/SirCypkowskyy/ExactDocs) for the full documentation.
@@ -0,0 +1,11 @@
1
+ # exactdocs
2
+
3
+ Self-hosted, version-accurate documentation for AI coding agents: an MCP server that serves
4
+ the right docs for the right library version, verbatim and with sources.
5
+
6
+ ```bash
7
+ uvx exactdocs serve # HTTP: web UI + MCP on http://localhost:3000
8
+ uvx exactdocs serve --stdio # MCP over stdio
9
+ ```
10
+
11
+ See the [project README](https://github.com/SirCypkowskyy/ExactDocs) for the full documentation.
@@ -0,0 +1,20 @@
1
+ Feature: Library catalog
2
+ As an AI coding agent
3
+ I want to know which libraries and versions ExactDocs has indexed
4
+ So that I only ask for documentation that actually exists
5
+
6
+ Background:
7
+ Given ExactDocs is running with the demo catalog
8
+
9
+ Scenario: Listing indexed libraries
10
+ When I list the libraries over the REST API
11
+ Then the response status is 200
12
+ And the libraries are:
13
+ | name | versions |
14
+ | fastapi | 0.115 |
15
+ | react | 19.1 |
16
+
17
+ Scenario: Asking for a library that is not indexed
18
+ When I request the library "vue"
19
+ Then the response status is 404
20
+ And the error code is "not_found"
@@ -0,0 +1,17 @@
1
+ Feature: Version-pinned documentation search
2
+ As an AI coding agent
3
+ I want search to be pinned to the exact library version I use
4
+ So that I never get a plausible answer for the wrong version
5
+
6
+ Background:
7
+ Given ExactDocs is running with the demo catalog
8
+
9
+ Scenario: The version is a hard filter, not a ranking hint
10
+ When I search "react" version "18.3" for "useFormState"
11
+ Then the response status is 404
12
+ And the error code is "not_found"
13
+
14
+ Scenario: An indexed version answers, even with no matching excerpt
15
+ When I search "react" version "19.1" for "useActionState"
16
+ Then the response status is 200
17
+ And I get 0 excerpts
@@ -0,0 +1,56 @@
1
+ """Steps that drive ExactDocs through its public HTTP API, like a real client would."""
2
+
3
+ from contextlib import ExitStack
4
+
5
+ from behave import given, then, when
6
+ from behave.runner import Context
7
+ from fastapi.testclient import TestClient
8
+
9
+ from exactdocs.bootstrap.container import Container
10
+ from exactdocs.bootstrap.http import create_app
11
+ from exactdocs.bootstrap.settings import Settings
12
+
13
+
14
+ @given("ExactDocs is running with the demo catalog")
15
+ def step_running(context: Context) -> None:
16
+ stack = ExitStack()
17
+ context.add_cleanup(stack.close) # runs the app's shutdown after the scenario
18
+ context.client = stack.enter_context(TestClient(create_app(Container.build(Settings()))))
19
+
20
+
21
+ @when("I list the libraries over the REST API")
22
+ def step_list(context: Context) -> None:
23
+ context.response = context.client.get("/api/v1/libraries")
24
+
25
+
26
+ @when('I request the library "{name}"')
27
+ def step_get(context: Context, name: str) -> None:
28
+ context.response = context.client.get(f"/api/v1/libraries/{name}")
29
+
30
+
31
+ @when('I search "{library}" version "{version}" for "{query}"')
32
+ def step_search(context: Context, library: str, version: str, query: str) -> None:
33
+ params = {"library": library, "version": version, "query": query}
34
+ context.response = context.client.get("/api/v1/search", params=params)
35
+
36
+
37
+ @then("the response status is {status:d}")
38
+ def step_status(context: Context, status: int) -> None:
39
+ assert context.response.status_code == status, context.response.text
40
+
41
+
42
+ @then('the error code is "{code}"')
43
+ def step_error(context: Context, code: str) -> None:
44
+ assert context.response.json()["error"] == code
45
+
46
+
47
+ @then("the libraries are:")
48
+ def step_libraries(context: Context) -> None:
49
+ expected = [(row["name"], row["versions"].split(", ")) for row in context.table or []]
50
+ actual = [(lib["name"], lib["versions"]) for lib in context.response.json()["libraries"]]
51
+ assert actual == expected, actual
52
+
53
+
54
+ @then("I get {count:d} excerpts")
55
+ def step_excerpts(context: Context, count: int) -> None:
56
+ assert len(context.response.json()["excerpts"]) == count
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "exactdocs"
3
+ dynamic = ["version", "dependencies"]
4
+ description = "Self-hosted, version-accurate documentation for AI coding agents (MCP server)."
5
+ readme = "README.md"
6
+ license = "Apache-2.0"
7
+ requires-python = ">=3.14"
8
+ authors = [{ name = "Cyprian Gburek" }]
9
+ keywords = ["mcp", "documentation", "rag", "ai-agents", "fastmcp"]
10
+ classifiers = [
11
+ "Development Status :: 2 - Pre-Alpha",
12
+ "Framework :: FastAPI",
13
+ "Programming Language :: Python :: 3.14",
14
+ "Typing :: Typed",
15
+ ]
16
+
17
+ [project.scripts]
18
+ exactdocs = "exactdocs.bootstrap.cli:main"
19
+
20
+ [project.urls]
21
+ Repository = "https://github.com/SirCypkowskyy/ExactDocs"
22
+ Issues = "https://github.com/SirCypkowskyy/ExactDocs/issues"
23
+
24
+ [build-system]
25
+ requires = ["hatchling>=1.27", "uv-dynamic-versioning>=0.11"]
26
+ build-backend = "hatchling.build"
27
+
28
+ [tool.hatch.version]
29
+ source = "uv-dynamic-versioning"
30
+
31
+ [tool.hatch.metadata.hooks.uv-dynamic-versioning]
32
+ # The kernel is released in lockstep with the app.
33
+ dependencies = [
34
+ "exactdocs-kernel=={{ version }}",
35
+ "cyclopts>=4",
36
+ "fastapi>=0.120",
37
+ "fastmcp>=4",
38
+ "mcp>=2",
39
+ "pydantic>=2.12",
40
+ "pydantic-settings>=2.11",
41
+ "uvicorn[standard]>=0.38",
42
+ ]
43
+
44
+ [tool.uv-dynamic-versioning]
45
+ vcs = "git"
46
+ style = "pep440"
47
+ fallback-version = "0.0.0"
48
+
49
+ [tool.hatch.build.targets.wheel]
50
+ packages = ["src/exactdocs"]
51
+ # The web UI is built by `pnpm build` and copied here in CI/Docker; it is gitignored.
52
+ artifacts = ["src/exactdocs/_web/**"]
53
+
54
+ [tool.hatch.build.targets.sdist]
55
+ artifacts = ["src/exactdocs/_web/**"]
@@ -0,0 +1,5 @@
1
+ """ExactDocs: self-hosted, version-accurate documentation for AI coding agents."""
2
+
3
+ from exactdocs._version import __version__
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1,3 @@
1
+ from exactdocs.bootstrap.cli import main
2
+
3
+ main()
@@ -0,0 +1,6 @@
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ try:
4
+ __version__ = version("exactdocs")
5
+ except PackageNotFoundError: # running from a source tree without installed metadata
6
+ __version__ = "0.0.0"