docsgraph 0.1.0a2__tar.gz → 0.1.0a3__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 (152) hide show
  1. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/workflows/ci.yml +1 -1
  2. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/workflows/release.yml +56 -6
  3. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CHANGELOG.md +10 -1
  4. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/PKG-INFO +21 -5
  5. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/README.md +20 -4
  6. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/release-checklist.md +27 -10
  7. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/pyproject.toml +6 -1
  8. docsgraph-0.1.0a3/scripts/verify_pypi_install.py +185 -0
  9. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/__init__.py +1 -1
  10. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/cli/app.py +199 -0
  11. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/repo_search.py +1 -1
  12. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_cli.py +76 -0
  13. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.cairn/config.toml +0 -0
  14. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.env.example +0 -0
  15. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  16. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  17. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  18. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  19. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/dependabot.yml +0 -0
  20. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/workflows/repo-regression.yml +0 -0
  21. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.gitignore +0 -0
  22. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/ARCHITECTURE.md +0 -0
  23. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CLAUDE.md +0 -0
  24. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CODE_OF_CONDUCT.md +0 -0
  25. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CONTRIBUTING.md +0 -0
  26. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/LICENSE +0 -0
  27. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/PRODUCT.md +0 -0
  28. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/ROADMAP.md +0 -0
  29. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/SECURITY.md +0 -0
  30. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/benchmarks/README.md +0 -0
  31. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/benchmarks/architecture.toml +0 -0
  32. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/assets/cairn-demo.svg +0 -0
  33. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/canvas.html +0 -0
  34. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/decisions/0000-template.md +0 -0
  35. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/decisions/0001-foundation.md +0 -0
  36. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/golden-docs-standard.md +0 -0
  37. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/inspector-principle.html +0 -0
  38. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/repo-lifecycle-canvas.html +0 -0
  39. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/specs/mcp-tools.md +0 -0
  40. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/examples/hero-demo.md +0 -0
  41. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/examples/real-llm-doubao.md +0 -0
  42. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/scripts/eval_repos.py +0 -0
  43. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/scripts/smoke_many_repos.py +0 -0
  44. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/__init__.py +0 -0
  45. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/baseline.py +0 -0
  46. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/dataset.py +0 -0
  47. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/judge.py +0 -0
  48. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/metrics.py +0 -0
  49. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/report.py +0 -0
  50. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/runner.py +0 -0
  51. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/cli/__init__.py +0 -0
  52. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/cli/config.py +0 -0
  53. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/core/__init__.py +0 -0
  54. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/core/errors.py +0 -0
  55. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/core/types.py +0 -0
  56. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/__init__.py +0 -0
  57. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/base.py +0 -0
  58. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/doubao.py +0 -0
  59. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/fake.py +0 -0
  60. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/openai_compatible.py +0 -0
  61. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/engine/__init__.py +0 -0
  62. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/engine/indexer.py +0 -0
  63. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/engine/manifest.py +0 -0
  64. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/__init__.py +0 -0
  65. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/base.py +0 -0
  66. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/fake.py +0 -0
  67. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/heuristic.py +0 -0
  68. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/__init__.py +0 -0
  69. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/entities.py +0 -0
  70. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/summaries.py +0 -0
  71. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/tree.py +0 -0
  72. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/vectors.py +0 -0
  73. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/xrefs.py +0 -0
  74. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/__init__.py +0 -0
  75. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/base.py +0 -0
  76. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/markdown.py +0 -0
  77. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/markitdown.py +0 -0
  78. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/pdf.py +0 -0
  79. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/inspection.py +0 -0
  80. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/mcp/__init__.py +0 -0
  81. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/mcp/schemas.py +0 -0
  82. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/mcp/server.py +0 -0
  83. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/providers.py +0 -0
  84. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/py.typed +0 -0
  85. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/repo.py +0 -0
  86. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/__init__.py +0 -0
  87. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/base.py +0 -0
  88. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/cache.py +0 -0
  89. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/fake.py +0 -0
  90. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/openai_compatible.py +0 -0
  91. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/prompts.py +0 -0
  92. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/__init__.py +0 -0
  93. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/base.py +0 -0
  94. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/find_mentions.py +0 -0
  95. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/get_related.py +0 -0
  96. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/get_section.py +0 -0
  97. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/outline.py +0 -0
  98. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/read_range.py +0 -0
  99. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/search_keyword.py +0 -0
  100. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/search_semantic.py +0 -0
  101. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/__init__.py +0 -0
  102. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/base.py +0 -0
  103. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/fake.py +0 -0
  104. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/heuristic.py +0 -0
  105. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/__init__.py +0 -0
  106. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/conftest.py +0 -0
  107. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/empty.md +0 -0
  108. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/nested.md +0 -0
  109. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/no_headings.md +0 -0
  110. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/simple.md +0 -0
  111. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/with_frontmatter.md +0 -0
  112. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/__init__.py +0 -0
  113. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/conftest.py +0 -0
  114. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_baseline.py +0 -0
  115. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_dataset.py +0 -0
  116. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_judge.py +0 -0
  117. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_metrics.py +0 -0
  118. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_runner.py +0 -0
  119. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_cli_config.py +0 -0
  120. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_embed_doubao.py +0 -0
  121. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_embed_fake.py +0 -0
  122. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_embed_openai_compatible.py +0 -0
  123. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_engine_indexer.py +0 -0
  124. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_engine_manifest.py +0 -0
  125. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_entities_builder.py +0 -0
  126. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_entity_heuristic.py +0 -0
  127. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_markdown_parser.py +0 -0
  128. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_markitdown_parser.py +0 -0
  129. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_mcp_server.py +0 -0
  130. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_pdf_parser.py +0 -0
  131. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_repo.py +0 -0
  132. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_repo_eval_gates.py +0 -0
  133. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summaries_builder.py +0 -0
  134. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summaries_reader.py +0 -0
  135. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_cache.py +0 -0
  136. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_fake.py +0 -0
  137. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_openai_compatible.py +0 -0
  138. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_prompts.py +0 -0
  139. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_document_index.py +0 -0
  140. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_find_mentions.py +0 -0
  141. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_get_related.py +0 -0
  142. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_get_section.py +0 -0
  143. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_outline.py +0 -0
  144. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_read_range.py +0 -0
  145. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_search_keyword.py +0 -0
  146. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_search_semantic.py +0 -0
  147. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tree_builder.py +0 -0
  148. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_types.py +0 -0
  149. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_vectors_builder.py +0 -0
  150. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_vectors_reader.py +0 -0
  151. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_xref_heuristic.py +0 -0
  152. {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_xrefs_builder.py +0 -0
@@ -38,7 +38,7 @@ jobs:
38
38
  run: ruff check .
39
39
 
40
40
  - name: mypy --strict
41
- run: mypy src tests
41
+ run: mypy --python-version "${{ matrix.python-version }}" src tests
42
42
 
43
43
  - name: pytest
44
44
  run: pytest
@@ -6,9 +6,36 @@ on:
6
6
  - "v*"
7
7
 
8
8
  jobs:
9
+ verify:
10
+ name: lint + types + tests
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.13"
19
+ cache: pip
20
+
21
+ - name: Install package + dev extras
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ python -m pip install -e ".[dev]"
25
+
26
+ - name: ruff
27
+ run: ruff check .
28
+
29
+ - name: mypy --strict
30
+ run: mypy --python-version "3.13" src tests
31
+
32
+ - name: pytest
33
+ run: pytest
34
+
9
35
  build:
10
36
  name: Build wheel + sdist for ${{ github.ref_name }}
11
37
  runs-on: ubuntu-latest
38
+ needs: verify
12
39
  steps:
13
40
  - uses: actions/checkout@v4
14
41
 
@@ -36,13 +63,11 @@ jobs:
36
63
  name: Publish to PyPI
37
64
  runs-on: ubuntu-latest
38
65
  needs: build
39
- # Trusted publishing requires the PyPI project to opt into
40
- # GitHub OIDC publishing under Settings → Publishing.
41
- # Until then, leave this job disabled by editing the `if`.
42
- if: ${{ false }}
66
+ # Trusted publishing requires the PyPI `docsgraph` project to trust this
67
+ # GitHub workflow/environment under Settings → Publishing.
43
68
  environment:
44
69
  name: pypi
45
- url: https://pypi.org/p/cairn
70
+ url: https://pypi.org/p/docsgraph
46
71
  permissions:
47
72
  id-token: write
48
73
  steps:
@@ -55,10 +80,35 @@ jobs:
55
80
  - name: Publish to PyPI
56
81
  uses: pypa/gh-action-pypi-publish@release/v1
57
82
 
83
+ verify-pypi-install:
84
+ name: Verify install from PyPI
85
+ runs-on: ubuntu-latest
86
+ needs: publish-pypi
87
+ steps:
88
+ - uses: actions/checkout@v4
89
+
90
+ - name: Set up Python
91
+ uses: actions/setup-python@v5
92
+ with:
93
+ python-version: "3.12"
94
+ cache: pip
95
+
96
+ - name: Verify published package from official index
97
+ run: |
98
+ version="${GITHUB_REF_NAME#v}"
99
+ for attempt in 1 2 3 4 5; do
100
+ if python scripts/verify_pypi_install.py --version "$version" --repo . --sync-repo; then
101
+ exit 0
102
+ fi
103
+ echo "PyPI install verification failed on attempt $attempt; retrying..."
104
+ sleep 30
105
+ done
106
+ python scripts/verify_pypi_install.py --version "$version" --repo . --sync-repo
107
+
58
108
  github-release:
59
109
  name: Attach artifacts to GitHub release
60
110
  runs-on: ubuntu-latest
61
- needs: build
111
+ needs: [build, publish-pypi, verify-pypi-install]
62
112
  permissions:
63
113
  contents: write
64
114
  steps:
@@ -41,6 +41,10 @@ All notable changes to Cairn. Format follows
41
41
  freshness; `cairn mcp config` prints MCP snippets for Claude, Cursor, Codex,
42
42
  and Goose. `cairn serve --repo <path>` makes generated configs independent
43
43
  from the client's working directory.
44
+ - **Agent self-install command.** `docsgraph install` writes the Cairn MCP
45
+ server config for Codex, Claude, Cursor, or Goose, while
46
+ `docsgraph install --dry-run` prints the target path and config without
47
+ touching disk.
44
48
  - **Public repo smoke evaluator.** `scripts/eval_repos.py` reproduces the
45
49
  uv / MCP Python SDK / FastAPI template repo-document smoke tests used for
46
50
  release readiness.
@@ -50,7 +54,10 @@ All notable changes to Cairn. Format follows
50
54
  - **Golden documentation standard.** `docs/golden-docs-standard.md` publishes
51
55
  the repo-doc shapes Cairn rewards and the tuning policy maintainers must
52
56
  follow when mature-repository smoke runs expose quality gaps.
53
- - **Optional MarkItDown ingestion.** Installing `cairn[markitdown]` lets Cairn
57
+ - **PyPI installation verifier.** `scripts/verify_pypi_install.py` installs a
58
+ released `docsgraph` wheel from the official Python index into a clean
59
+ temporary environment and checks both `docsgraph` and `cairn` console scripts.
60
+ - **Optional MarkItDown ingestion.** Installing `docsgraph[markitdown]` lets Cairn
54
61
  convert local DOCX, PPTX, XLSX, HTML, CSV, JSON, XML, EPUB, and related files
55
62
  to Markdown before indexing them through the canonical Markdown pipeline.
56
63
 
@@ -98,6 +105,8 @@ All notable changes to Cairn. Format follows
98
105
  Cairn product name while making the installed tool obvious and avoiding the
99
106
  unrelated package that already occupies `cairn`.
100
107
  - Strict mypy now passes across both `src` and `tests`.
108
+ - The release workflow now runs lint, type checks, tests, build validation, and
109
+ PyPI Trusted Publishing from the `pypi` GitHub environment on version tags.
101
110
 
102
111
  ## [0.1.0a2] — 2026-06-11
103
112
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docsgraph
3
- Version: 0.1.0a2
3
+ Version: 0.1.0a3
4
4
  Summary: Local-first documentation graph for AI agents. CodeGraph for docs, exposed through MCP.
5
5
  Project-URL: Homepage, https://github.com/jokeuncle/cairn
6
6
  Project-URL: Documentation, https://github.com/jokeuncle/cairn/tree/main/docs
@@ -260,7 +260,7 @@ Description-Content-Type: text/markdown
260
260
 
261
261
  [![CI](https://github.com/jokeuncle/cairn/actions/workflows/ci.yml/badge.svg)](https://github.com/jokeuncle/cairn/actions/workflows/ci.yml)
262
262
  [![License](https://img.shields.io/badge/license-Apache_2.0-blue.svg)](LICENSE)
263
- [![Version](https://img.shields.io/badge/version-0.1.0a2-blue.svg)](CHANGELOG.md)
263
+ [![Version](https://img.shields.io/badge/version-0.1.0a3-blue.svg)](CHANGELOG.md)
264
264
  [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
265
265
  [![MCP](https://img.shields.io/badge/MCP-native-7c3aed.svg)](https://modelcontextprotocol.io/)
266
266
 
@@ -282,7 +282,7 @@ The result: better retrieval accuracy, lower token spend, and a practical MCP
282
282
  tool layer between your project documentation and every AI coding agent you
283
283
  use. Local-first. Vendor-neutral. Designed for open-source repos.
284
284
 
285
- > 🚀 **Alpha — `0.1.0a2`.** Markdown + PDF ingest, all eight MCP tools,
285
+ > 🚀 **Alpha — `0.1.0a3`.** Markdown + PDF ingest, all eight MCP tools,
286
286
  > the full structure-aware index (tree + summaries + entities + xrefs +
287
287
  > vectors), repo-level `init/sync/status`, repo-scoped MCP with
288
288
  > `list_documents`, `search_documents`, `repo_context`, `repo_graph`, and
@@ -352,6 +352,22 @@ Or run it without installing:
352
352
  uvx docsgraph --help
353
353
  ```
354
354
 
355
+ AI agents that can run shell commands can install and wire Cairn into their own
356
+ MCP config. Start with a dry run, then write the config once the target path
357
+ looks right:
358
+
359
+ ```bash
360
+ uvx docsgraph init -y
361
+ uvx docsgraph sync --fake
362
+ uvx docsgraph install --client codex --dry-run --fake
363
+ uvx docsgraph install --client codex --yes --fake
364
+ ```
365
+
366
+ Use `--client claude`, `--client cursor`, or `--client goose` for other MCP
367
+ clients. `docsgraph install` writes the same server config that
368
+ `docsgraph mcp config` prints, with `command = "docsgraph"` and
369
+ `args = ["serve", "--repo", "..."]`.
370
+
355
371
  ### Repository Workflow
356
372
 
357
373
  Inside any repository:
@@ -442,7 +458,7 @@ Markdown parser. This expands coverage to formats such as DOCX, PPTX, XLSX,
442
458
  HTML, CSV, JSON, XML, and EPUB without making the base install heavy:
443
459
 
444
460
  ```bash
445
- .venv/bin/pip install -e ".[markitdown]"
461
+ pip install "docsgraph[markitdown]"
446
462
  .venv/bin/docsgraph init -y --force --markitdown
447
463
  .venv/bin/docsgraph sync --fake
448
464
  ```
@@ -657,7 +673,7 @@ choices we adopted, modified, or declined.
657
673
  | 4 — v0.4 polish for production | ☐ | DOCX/RTF/EPUB, VSCode extension, security review |
658
674
  | v1.0 GA | ☐ | All `PRODUCT.md` §7 success criteria met |
659
675
 
660
- Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **436 passing**,
676
+ Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **440 passing**,
661
677
  mypy strict clean, ruff clean.
662
678
 
663
679
  Maintainer release gate: [`docs/release-checklist.md`](docs/release-checklist.md).
@@ -6,7 +6,7 @@
6
6
 
7
7
  [![CI](https://github.com/jokeuncle/cairn/actions/workflows/ci.yml/badge.svg)](https://github.com/jokeuncle/cairn/actions/workflows/ci.yml)
8
8
  [![License](https://img.shields.io/badge/license-Apache_2.0-blue.svg)](LICENSE)
9
- [![Version](https://img.shields.io/badge/version-0.1.0a2-blue.svg)](CHANGELOG.md)
9
+ [![Version](https://img.shields.io/badge/version-0.1.0a3-blue.svg)](CHANGELOG.md)
10
10
  [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
11
11
  [![MCP](https://img.shields.io/badge/MCP-native-7c3aed.svg)](https://modelcontextprotocol.io/)
12
12
 
@@ -28,7 +28,7 @@ The result: better retrieval accuracy, lower token spend, and a practical MCP
28
28
  tool layer between your project documentation and every AI coding agent you
29
29
  use. Local-first. Vendor-neutral. Designed for open-source repos.
30
30
 
31
- > 🚀 **Alpha — `0.1.0a2`.** Markdown + PDF ingest, all eight MCP tools,
31
+ > 🚀 **Alpha — `0.1.0a3`.** Markdown + PDF ingest, all eight MCP tools,
32
32
  > the full structure-aware index (tree + summaries + entities + xrefs +
33
33
  > vectors), repo-level `init/sync/status`, repo-scoped MCP with
34
34
  > `list_documents`, `search_documents`, `repo_context`, `repo_graph`, and
@@ -98,6 +98,22 @@ Or run it without installing:
98
98
  uvx docsgraph --help
99
99
  ```
100
100
 
101
+ AI agents that can run shell commands can install and wire Cairn into their own
102
+ MCP config. Start with a dry run, then write the config once the target path
103
+ looks right:
104
+
105
+ ```bash
106
+ uvx docsgraph init -y
107
+ uvx docsgraph sync --fake
108
+ uvx docsgraph install --client codex --dry-run --fake
109
+ uvx docsgraph install --client codex --yes --fake
110
+ ```
111
+
112
+ Use `--client claude`, `--client cursor`, or `--client goose` for other MCP
113
+ clients. `docsgraph install` writes the same server config that
114
+ `docsgraph mcp config` prints, with `command = "docsgraph"` and
115
+ `args = ["serve", "--repo", "..."]`.
116
+
101
117
  ### Repository Workflow
102
118
 
103
119
  Inside any repository:
@@ -188,7 +204,7 @@ Markdown parser. This expands coverage to formats such as DOCX, PPTX, XLSX,
188
204
  HTML, CSV, JSON, XML, and EPUB without making the base install heavy:
189
205
 
190
206
  ```bash
191
- .venv/bin/pip install -e ".[markitdown]"
207
+ pip install "docsgraph[markitdown]"
192
208
  .venv/bin/docsgraph init -y --force --markitdown
193
209
  .venv/bin/docsgraph sync --fake
194
210
  ```
@@ -403,7 +419,7 @@ choices we adopted, modified, or declined.
403
419
  | 4 — v0.4 polish for production | ☐ | DOCX/RTF/EPUB, VSCode extension, security review |
404
420
  | v1.0 GA | ☐ | All `PRODUCT.md` §7 success criteria met |
405
421
 
406
- Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **436 passing**,
422
+ Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **440 passing**,
407
423
  mypy strict clean, ruff clean.
408
424
 
409
425
  Maintainer release gate: [`docs/release-checklist.md`](docs/release-checklist.md).
@@ -37,20 +37,16 @@ UV_PROJECT_ENVIRONMENT=/tmp/cairn-test-venv-py313 uv run --python 3.13 --extra d
37
37
  UV_PROJECT_ENVIRONMENT=/tmp/cairn-test-venv-py313 uv run --python 3.13 --extra dev pytest
38
38
 
39
39
  rm -rf /tmp/cairn-dist
40
- UV_PROJECT_ENVIRONMENT=/tmp/cairn-build-venv-py313 \
41
- uv run --python 3.13 --with build --with twine \
42
- python -m build --outdir /tmp/cairn-dist
43
- UV_PROJECT_ENVIRONMENT=/tmp/cairn-build-venv-py313 \
44
- uv run --python 3.13 --with build --with twine \
45
- python -m twine check /tmp/cairn-dist/*
40
+ uv build --out-dir /tmp/cairn-dist
41
+ uv publish --dry-run /tmp/cairn-dist/*
46
42
  ```
47
43
 
48
44
  Expected current gate:
49
45
 
50
46
  - `ruff check .`: pass
51
47
  - `mypy src tests`: pass
52
- - `pytest`: 436 passing
53
- - `twine check`: wheel and sdist pass
48
+ - `pytest`: 440 passing
49
+ - `uv publish --dry-run`: wheel and sdist pass upload validation
54
50
 
55
51
  ## Dogfood Checks
56
52
 
@@ -121,6 +117,27 @@ export CAIRN_EMBED_MODEL=doubao-embedding-vision-251215
121
117
  The corresponding API key variables must be set locally, but real values must
122
118
  never appear in git, shell history snippets, benchmark reports, or CI logs.
123
119
 
120
+ ## Trusted Publishing
121
+
122
+ Public PyPI publishing must use GitHub OIDC Trusted Publishing, not a long-lived
123
+ API token in a local shell. Configure PyPI before pushing a release tag:
124
+
125
+ - Project: `docsgraph`
126
+ - Owner / repository: `jokeuncle/cairn`
127
+ - Workflow: `.github/workflows/release.yml`
128
+ - Environment: `pypi`
129
+
130
+ In GitHub, create the `pypi` environment and require maintainer approval if the
131
+ repository is not fully locked down. Revoke any account-wide PyPI token used for
132
+ manual bootstrapping after the first project-scoped setup is in place.
133
+
134
+ After the tag workflow publishes, verify the official source install from a
135
+ clean temporary environment:
136
+
137
+ ```bash
138
+ python scripts/verify_pypi_install.py --version "$(uv run docsgraph version)" --repo . --sync-repo
139
+ ```
140
+
124
141
  ## Secret And Generated-File Audit
125
142
 
126
143
  ```bash
@@ -144,5 +161,5 @@ git push origin main --tags
144
161
  ```
145
162
 
146
163
  The release workflow builds wheel/sdist and attaches them to the GitHub
147
- release. PyPI publishing is intentionally disabled until trusted publishing is
148
- configured for the package.
164
+ release. It also publishes to PyPI through Trusted Publishing when the `pypi`
165
+ environment is approved and the PyPI project trusts this workflow.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "docsgraph"
7
- version = "0.1.0a2"
7
+ version = "0.1.0a3"
8
8
  description = "Local-first documentation graph for AI agents. CodeGraph for docs, exposed through MCP."
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -116,6 +116,11 @@ ignore_missing_imports = true
116
116
  module = ["markitdown", "markitdown.*"]
117
117
  ignore_missing_imports = true
118
118
 
119
+ [[tool.mypy.overrides]]
120
+ module = ["numpy", "numpy.*"]
121
+ follow_imports = "skip"
122
+ ignore_missing_imports = true
123
+
119
124
  [tool.pytest.ini_options]
120
125
  testpaths = ["tests"]
121
126
  addopts = "-ra --strict-markers"
@@ -0,0 +1,185 @@
1
+ """Verify a published docsgraph package from the public Python index."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ import tempfile
10
+ import tomllib
11
+ from pathlib import Path
12
+
13
+
14
+ def main() -> int:
15
+ parser = argparse.ArgumentParser()
16
+ parser.add_argument(
17
+ "--version",
18
+ default=None,
19
+ help="Version to install. Defaults to the current pyproject version.",
20
+ )
21
+ parser.add_argument(
22
+ "--index-url",
23
+ default="https://pypi.org/simple",
24
+ help="Python package index URL to install from.",
25
+ )
26
+ parser.add_argument(
27
+ "--repo",
28
+ type=Path,
29
+ default=None,
30
+ help="Optional initialized repo to smoke-test MCP config against.",
31
+ )
32
+ parser.add_argument(
33
+ "--sync-repo",
34
+ action="store_true",
35
+ help="Run docsgraph sync/status/query in --repo after installing.",
36
+ )
37
+ args = parser.parse_args()
38
+
39
+ root = Path(__file__).resolve().parents[1]
40
+ version = args.version or _project_version(root / "pyproject.toml")
41
+ requirement = f"docsgraph=={version}"
42
+
43
+ with tempfile.TemporaryDirectory(prefix="docsgraph-pypi-") as tmp:
44
+ venv = Path(tmp) / "venv"
45
+ python = _create_venv(venv)
46
+ _install(python, args.index_url, requirement)
47
+
48
+ docsgraph = _script_path(venv, "docsgraph")
49
+ cairn = _script_path(venv, "cairn")
50
+ _run([str(docsgraph), "--help"])
51
+ _run([str(cairn), "--help"])
52
+ _run([str(docsgraph), "version"], expected=version)
53
+
54
+ _run(
55
+ [
56
+ str(python),
57
+ "-c",
58
+ (
59
+ "from importlib.metadata import metadata, version; "
60
+ "m=metadata('docsgraph'); "
61
+ "print(m['Name']); print(version('docsgraph'))"
62
+ ),
63
+ ],
64
+ expected=f"docsgraph\n{version}",
65
+ )
66
+
67
+ if args.repo is not None:
68
+ repo = args.repo.resolve()
69
+ _run(
70
+ [
71
+ str(docsgraph),
72
+ "mcp",
73
+ "config",
74
+ "--client",
75
+ "codex",
76
+ "--repo",
77
+ str(repo),
78
+ "--fake",
79
+ ],
80
+ cwd=repo,
81
+ expected='command = "docsgraph"',
82
+ )
83
+ if args.sync_repo:
84
+ _run([str(docsgraph), "sync", "--fake"], cwd=repo)
85
+ _run([str(docsgraph), "status"], cwd=repo, expected="documents:")
86
+ _run(
87
+ [
88
+ str(docsgraph),
89
+ "query",
90
+ "repo",
91
+ "what is this project?",
92
+ "--fake",
93
+ ],
94
+ cwd=repo,
95
+ expected='"hits"',
96
+ )
97
+
98
+ print(f"verified {requirement} from {args.index_url}")
99
+ return 0
100
+
101
+
102
+ def _project_version(pyproject: Path) -> str:
103
+ data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
104
+ return str(data["project"]["version"])
105
+
106
+
107
+ def _create_venv(venv: Path) -> Path:
108
+ uv = shutil.which("uv")
109
+ if uv:
110
+ _run([uv, "venv", str(venv)])
111
+ return _venv_python(venv)
112
+
113
+ _run([sys.executable, "-m", "venv", str(venv)])
114
+ python = _venv_python(venv)
115
+ _run([str(python), "-m", "ensurepip", "--upgrade"])
116
+ return python
117
+
118
+
119
+ def _install(python: Path, index_url: str, requirement: str) -> None:
120
+ uv = shutil.which("uv")
121
+ if uv:
122
+ _run(
123
+ [
124
+ uv,
125
+ "pip",
126
+ "install",
127
+ "--python",
128
+ str(python),
129
+ "--index-url",
130
+ index_url,
131
+ requirement,
132
+ ]
133
+ )
134
+ return
135
+ _run(
136
+ [
137
+ str(python),
138
+ "-m",
139
+ "pip",
140
+ "install",
141
+ "--index-url",
142
+ index_url,
143
+ requirement,
144
+ ]
145
+ )
146
+
147
+
148
+ def _venv_python(venv: Path) -> Path:
149
+ if sys.platform == "win32":
150
+ return venv / "Scripts" / "python.exe"
151
+ return venv / "bin" / "python"
152
+
153
+
154
+ def _script_path(venv: Path, name: str) -> Path:
155
+ suffix = ".exe" if sys.platform == "win32" else ""
156
+ directory = "Scripts" if sys.platform == "win32" else "bin"
157
+ return venv / directory / f"{name}{suffix}"
158
+
159
+
160
+ def _run(
161
+ cmd: list[str],
162
+ *,
163
+ cwd: Path | None = None,
164
+ expected: str | None = None,
165
+ ) -> str:
166
+ result = subprocess.run(
167
+ cmd,
168
+ cwd=cwd,
169
+ text=True,
170
+ stdout=subprocess.PIPE,
171
+ stderr=subprocess.STDOUT,
172
+ check=False,
173
+ )
174
+ if result.returncode != 0:
175
+ print(result.stdout, file=sys.stderr)
176
+ raise SystemExit(result.returncode)
177
+ if expected is not None and expected not in result.stdout:
178
+ print(result.stdout, file=sys.stderr)
179
+ msg = f"expected output to contain: {expected!r}"
180
+ raise SystemExit(msg)
181
+ return result.stdout
182
+
183
+
184
+ if __name__ == "__main__":
185
+ raise SystemExit(main())
@@ -1,5 +1,5 @@
1
1
  """Cairn — structure-aware, MCP-native retrieval for large documents."""
2
2
 
3
- __version__ = "0.1.0a2"
3
+ __version__ = "0.1.0a3"
4
4
 
5
5
  __all__ = ["__version__"]