pygrafito 0.8.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 (230) hide show
  1. pygrafito-0.8.0/.github/workflows/ci.yml +98 -0
  2. pygrafito-0.8.0/.github/workflows/docs.yml +70 -0
  3. pygrafito-0.8.0/.github/workflows/release.yml +88 -0
  4. pygrafito-0.8.0/.gitignore +220 -0
  5. pygrafito-0.8.0/.opencode/commands/opsx-apply.md +199 -0
  6. pygrafito-0.8.0/.opencode/commands/opsx-archive.md +261 -0
  7. pygrafito-0.8.0/.opencode/commands/opsx-explore.md +238 -0
  8. pygrafito-0.8.0/.opencode/commands/opsx-propose.md +168 -0
  9. pygrafito-0.8.0/.opencode/commands/opsx-sync.md +283 -0
  10. pygrafito-0.8.0/.opencode/commands/opsx-update.md +102 -0
  11. pygrafito-0.8.0/.opencode/skills/openspec-apply-change/SKILL.md +206 -0
  12. pygrafito-0.8.0/.opencode/skills/openspec-archive-change/SKILL.md +221 -0
  13. pygrafito-0.8.0/.opencode/skills/openspec-explore/SKILL.md +356 -0
  14. pygrafito-0.8.0/.opencode/skills/openspec-propose/SKILL.md +175 -0
  15. pygrafito-0.8.0/.opencode/skills/openspec-sync-specs/SKILL.md +290 -0
  16. pygrafito-0.8.0/.opencode/skills/openspec-update-change/SKILL.md +109 -0
  17. pygrafito-0.8.0/.vscode/extensions.json +5 -0
  18. pygrafito-0.8.0/.vscode/settings.json +3 -0
  19. pygrafito-0.8.0/AGENTS.md +76 -0
  20. pygrafito-0.8.0/CHANGELOG.md +255 -0
  21. pygrafito-0.8.0/LICENSE.txt +18 -0
  22. pygrafito-0.8.0/PKG-INFO +99 -0
  23. pygrafito-0.8.0/README.md +73 -0
  24. pygrafito-0.8.0/benchmarks/run.py +701 -0
  25. pygrafito-0.8.0/docs/_static/custom.css +12 -0
  26. pygrafito-0.8.0/docs/api/admin.md +45 -0
  27. pygrafito-0.8.0/docs/api/errors.md +135 -0
  28. pygrafito-0.8.0/docs/api/graph.md +252 -0
  29. pygrafito-0.8.0/docs/api/index.md +78 -0
  30. pygrafito-0.8.0/docs/api/model.md +97 -0
  31. pygrafito-0.8.0/docs/api/query.md +94 -0
  32. pygrafito-0.8.0/docs/conf.py +106 -0
  33. pygrafito-0.8.0/docs/getting-started/quickstart.md +156 -0
  34. pygrafito-0.8.0/docs/guides/constraints.md +133 -0
  35. pygrafito-0.8.0/docs/guides/embedding.md +148 -0
  36. pygrafito-0.8.0/docs/guides/importing.md +191 -0
  37. pygrafito-0.8.0/docs/guides/indexes.md +116 -0
  38. pygrafito-0.8.0/docs/guides/interop.md +115 -0
  39. pygrafito-0.8.0/docs/guides/querying.md +214 -0
  40. pygrafito-0.8.0/docs/guides/shell.md +161 -0
  41. pygrafito-0.8.0/docs/index.md +106 -0
  42. pygrafito-0.8.0/docs/reference/cli.md +417 -0
  43. pygrafito-0.8.0/docs/reference/embedding-contract.md +127 -0
  44. pygrafito-0.8.0/docs/reference/index-behavior.md +141 -0
  45. pygrafito-0.8.0/docs/reference/performance.md +137 -0
  46. pygrafito-0.8.0/docs/reference/query-language.md +697 -0
  47. pygrafito-0.8.0/docs/reference/snapshot-format.md +231 -0
  48. pygrafito-0.8.0/openspec/changes/archive/.gitkeep +0 -0
  49. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-add-embedded-property-graph/.openspec.yaml +2 -0
  50. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-add-embedded-property-graph/design.md +279 -0
  51. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-add-embedded-property-graph/proposal.md +34 -0
  52. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-add-embedded-property-graph/specs/graph-traversal/spec.md +159 -0
  53. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-add-embedded-property-graph/specs/property-graph/spec.md +200 -0
  54. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-add-embedded-property-graph/tasks.md +43 -0
  55. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-harden-foundation/.openspec.yaml +2 -0
  56. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-harden-foundation/design.md +193 -0
  57. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-harden-foundation/proposal.md +52 -0
  58. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-harden-foundation/specs/property-graph/spec.md +40 -0
  59. pygrafito-0.8.0/openspec/changes/archive/2026-10-22-harden-foundation/tasks.md +85 -0
  60. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-batch-ingestion/.openspec.yaml +2 -0
  61. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-batch-ingestion/design.md +248 -0
  62. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-batch-ingestion/proposal.md +64 -0
  63. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-batch-ingestion/specs/graph-import/spec.md +209 -0
  64. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-batch-ingestion/specs/graph-query-language/spec.md +380 -0
  65. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-batch-ingestion/specs/graph-shell/spec.md +47 -0
  66. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-batch-ingestion/tasks.md +91 -0
  67. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-bounded-traversal/.openspec.yaml +2 -0
  68. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-bounded-traversal/design.md +134 -0
  69. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-bounded-traversal/proposal.md +57 -0
  70. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-bounded-traversal/specs/graph-traversal/spec.md +72 -0
  71. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-bounded-traversal/tasks.md +31 -0
  72. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-data-interop/.openspec.yaml +2 -0
  73. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-data-interop/design.md +249 -0
  74. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-data-interop/proposal.md +73 -0
  75. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-data-interop/specs/graph-interop/spec.md +396 -0
  76. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-data-interop/specs/graph-shell/spec.md +123 -0
  77. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-data-interop/tasks.md +100 -0
  78. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-embedding-contract/.openspec.yaml +2 -0
  79. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-embedding-contract/design.md +295 -0
  80. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-embedding-contract/proposal.md +77 -0
  81. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-embedding-contract/specs/graph-constraints/spec.md +250 -0
  82. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-embedding-contract/specs/property-graph/spec.md +145 -0
  83. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-embedding-contract/tasks.md +47 -0
  84. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-graph-shell/.openspec.yaml +2 -0
  85. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-graph-shell/design.md +350 -0
  86. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-graph-shell/proposal.md +67 -0
  87. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-graph-shell/specs/graph-shell/spec.md +486 -0
  88. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-graph-shell/specs/property-graph/spec.md +123 -0
  89. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-graph-shell/tasks.md +87 -0
  90. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-property-indexes/.openspec.yaml +2 -0
  91. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-property-indexes/design.md +176 -0
  92. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-property-indexes/proposal.md +68 -0
  93. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-property-indexes/specs/graph-indexes/spec.md +216 -0
  94. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-property-indexes/tasks.md +44 -0
  95. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-query-composition/.openspec.yaml +2 -0
  96. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-query-composition/design.md +335 -0
  97. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-query-composition/proposal.md +99 -0
  98. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-query-composition/specs/graph-query-language/spec.md +277 -0
  99. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-query-composition/tasks.md +65 -0
  100. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-read-query-language/.openspec.yaml +2 -0
  101. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-read-query-language/design.md +333 -0
  102. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-read-query-language/proposal.md +64 -0
  103. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-read-query-language/specs/graph-query-language/spec.md +473 -0
  104. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-read-query-language/tasks.md +83 -0
  105. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-write-clauses/.openspec.yaml +2 -0
  106. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-write-clauses/design.md +289 -0
  107. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-write-clauses/proposal.md +70 -0
  108. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-write-clauses/specs/graph-query-language/spec.md +374 -0
  109. pygrafito-0.8.0/openspec/changes/archive/2026-10-23-add-write-clauses/tasks.md +67 -0
  110. pygrafito-0.8.0/openspec/changes/archive/2026-10-24-add-sphinx-documentation/.openspec.yaml +3 -0
  111. pygrafito-0.8.0/openspec/changes/archive/2026-10-24-add-sphinx-documentation/design.md +264 -0
  112. pygrafito-0.8.0/openspec/changes/archive/2026-10-24-add-sphinx-documentation/proposal.md +60 -0
  113. pygrafito-0.8.0/openspec/changes/archive/2026-10-24-add-sphinx-documentation/tasks.md +125 -0
  114. pygrafito-0.8.0/openspec/config.yaml +32 -0
  115. pygrafito-0.8.0/openspec/specs/.gitkeep +0 -0
  116. pygrafito-0.8.0/openspec/specs/graph-constraints/spec.md +250 -0
  117. pygrafito-0.8.0/openspec/specs/graph-import/spec.md +209 -0
  118. pygrafito-0.8.0/openspec/specs/graph-indexes/spec.md +216 -0
  119. pygrafito-0.8.0/openspec/specs/graph-interop/spec.md +396 -0
  120. pygrafito-0.8.0/openspec/specs/graph-query-language/spec.md +1211 -0
  121. pygrafito-0.8.0/openspec/specs/graph-shell/spec.md +650 -0
  122. pygrafito-0.8.0/openspec/specs/graph-traversal/spec.md +217 -0
  123. pygrafito-0.8.0/openspec/specs/property-graph/spec.md +488 -0
  124. pygrafito-0.8.0/pyproject.toml +133 -0
  125. pygrafito-0.8.0/src/pygrafito/__about__.py +6 -0
  126. pygrafito-0.8.0/src/pygrafito/__init__.py +71 -0
  127. pygrafito-0.8.0/src/pygrafito/__main__.py +9 -0
  128. pygrafito-0.8.0/src/pygrafito/cli/__init__.py +4 -0
  129. pygrafito-0.8.0/src/pygrafito/cli/app.py +184 -0
  130. pygrafito-0.8.0/src/pygrafito/cli/commands.py +927 -0
  131. pygrafito-0.8.0/src/pygrafito/cli/formatting.py +529 -0
  132. pygrafito-0.8.0/src/pygrafito/cli/reader.py +170 -0
  133. pygrafito-0.8.0/src/pygrafito/cli/session.py +667 -0
  134. pygrafito-0.8.0/src/pygrafito/cli/shell.py +219 -0
  135. pygrafito-0.8.0/src/pygrafito/engine/__init__.py +4 -0
  136. pygrafito-0.8.0/src/pygrafito/engine/graph.py +1265 -0
  137. pygrafito-0.8.0/src/pygrafito/engine/importing.py +644 -0
  138. pygrafito-0.8.0/src/pygrafito/engine/interop.py +973 -0
  139. pygrafito-0.8.0/src/pygrafito/engine/query/__init__.py +4 -0
  140. pygrafito-0.8.0/src/pygrafito/engine/query/ast.py +623 -0
  141. pygrafito-0.8.0/src/pygrafito/engine/query/compiler.py +1186 -0
  142. pygrafito-0.8.0/src/pygrafito/engine/query/executor.py +1657 -0
  143. pygrafito-0.8.0/src/pygrafito/engine/query/lexer.py +591 -0
  144. pygrafito-0.8.0/src/pygrafito/engine/query/mutation.py +768 -0
  145. pygrafito-0.8.0/src/pygrafito/engine/query/parser.py +1524 -0
  146. pygrafito-0.8.0/src/pygrafito/engine/query/pattern.py +608 -0
  147. pygrafito-0.8.0/src/pygrafito/engine/query/plan.py +278 -0
  148. pygrafito-0.8.0/src/pygrafito/engine/query/prepared.py +96 -0
  149. pygrafito-0.8.0/src/pygrafito/engine/query/results.py +186 -0
  150. pygrafito-0.8.0/src/pygrafito/engine/query/semantic.py +1470 -0
  151. pygrafito-0.8.0/src/pygrafito/engine/query/tokens.py +155 -0
  152. pygrafito-0.8.0/src/pygrafito/engine/query/values.py +1764 -0
  153. pygrafito-0.8.0/src/pygrafito/engine/transaction.py +547 -0
  154. pygrafito-0.8.0/src/pygrafito/engine/traversal.py +995 -0
  155. pygrafito-0.8.0/src/pygrafito/model.py +480 -0
  156. pygrafito-0.8.0/src/pygrafito/py.typed +0 -0
  157. pygrafito-0.8.0/src/pygrafito/storage/__init__.py +4 -0
  158. pygrafito-0.8.0/src/pygrafito/storage/codec.py +362 -0
  159. pygrafito-0.8.0/src/pygrafito/storage/connection.py +378 -0
  160. pygrafito-0.8.0/src/pygrafito/storage/constraints.py +854 -0
  161. pygrafito-0.8.0/src/pygrafito/storage/indexes.py +162 -0
  162. pygrafito-0.8.0/src/pygrafito/storage/nodes.py +617 -0
  163. pygrafito-0.8.0/src/pygrafito/storage/relationships.py +514 -0
  164. pygrafito-0.8.0/src/pygrafito/storage/schema.py +232 -0
  165. pygrafito-0.8.0/src/pygrafito/storage/views.py +203 -0
  166. pygrafito-0.8.0/tests/__init__.py +3 -0
  167. pygrafito-0.8.0/tests/cli/__init__.py +4 -0
  168. pygrafito-0.8.0/tests/cli/support.py +144 -0
  169. pygrafito-0.8.0/tests/cli/test_app.py +309 -0
  170. pygrafito-0.8.0/tests/cli/test_commands.py +800 -0
  171. pygrafito-0.8.0/tests/cli/test_formatting.py +217 -0
  172. pygrafito-0.8.0/tests/cli/test_interop_commands.py +401 -0
  173. pygrafito-0.8.0/tests/cli/test_package.py +34 -0
  174. pygrafito-0.8.0/tests/cli/test_reader.py +117 -0
  175. pygrafito-0.8.0/tests/cli/test_session.py +202 -0
  176. pygrafito-0.8.0/tests/cli/test_shell.py +273 -0
  177. pygrafito-0.8.0/tests/engine/__init__.py +4 -0
  178. pygrafito-0.8.0/tests/engine/query/__init__.py +4 -0
  179. pygrafito-0.8.0/tests/engine/query/test_api.py +191 -0
  180. pygrafito-0.8.0/tests/engine/query/test_ast.py +199 -0
  181. pygrafito-0.8.0/tests/engine/query/test_compiler.py +500 -0
  182. pygrafito-0.8.0/tests/engine/query/test_conformance.py +412 -0
  183. pygrafito-0.8.0/tests/engine/query/test_errors.py +89 -0
  184. pygrafito-0.8.0/tests/engine/query/test_executor.py +1040 -0
  185. pygrafito-0.8.0/tests/engine/query/test_lexer.py +199 -0
  186. pygrafito-0.8.0/tests/engine/query/test_parser.py +581 -0
  187. pygrafito-0.8.0/tests/engine/query/test_pattern_engine.py +225 -0
  188. pygrafito-0.8.0/tests/engine/query/test_semantic.py +734 -0
  189. pygrafito-0.8.0/tests/engine/query/test_values.py +722 -0
  190. pygrafito-0.8.0/tests/engine/query/test_write_execution.py +369 -0
  191. pygrafito-0.8.0/tests/engine/test_capture.py +204 -0
  192. pygrafito-0.8.0/tests/engine/test_importing.py +312 -0
  193. pygrafito-0.8.0/tests/engine/test_neighborhood.py +111 -0
  194. pygrafito-0.8.0/tests/engine/test_paths.py +254 -0
  195. pygrafito-0.8.0/tests/engine/test_reachability.py +228 -0
  196. pygrafito-0.8.0/tests/engine/test_shortest_path.py +243 -0
  197. pygrafito-0.8.0/tests/engine/test_validation.py +221 -0
  198. pygrafito-0.8.0/tests/storage/__init__.py +4 -0
  199. pygrafito-0.8.0/tests/storage/test_deletion.py +163 -0
  200. pygrafito-0.8.0/tests/storage/test_frontier.py +145 -0
  201. pygrafito-0.8.0/tests/storage/test_indexes.py +172 -0
  202. pygrafito-0.8.0/tests/storage/test_nodes.py +277 -0
  203. pygrafito-0.8.0/tests/storage/test_relationships.py +298 -0
  204. pygrafito-0.8.0/tests/storage/test_schema.py +306 -0
  205. pygrafito-0.8.0/tests/test_benchmarks.py +36 -0
  206. pygrafito-0.8.0/tests/test_codec.py +324 -0
  207. pygrafito-0.8.0/tests/test_concurrency.py +648 -0
  208. pygrafito-0.8.0/tests/test_constraints.py +424 -0
  209. pygrafito-0.8.0/tests/test_docs_examples.py +112 -0
  210. pygrafito-0.8.0/tests/test_embedding.py +192 -0
  211. pygrafito-0.8.0/tests/test_explain.py +128 -0
  212. pygrafito-0.8.0/tests/test_graph.py +270 -0
  213. pygrafito-0.8.0/tests/test_import_integration.py +108 -0
  214. pygrafito-0.8.0/tests/test_index_transparency.py +148 -0
  215. pygrafito-0.8.0/tests/test_indexes.py +210 -0
  216. pygrafito-0.8.0/tests/test_integration.py +145 -0
  217. pygrafito-0.8.0/tests/test_interop_export.py +213 -0
  218. pygrafito-0.8.0/tests/test_interop_format.py +338 -0
  219. pygrafito-0.8.0/tests/test_interop_integration.py +91 -0
  220. pygrafito-0.8.0/tests/test_interop_restore.py +382 -0
  221. pygrafito-0.8.0/tests/test_interop_views.py +373 -0
  222. pygrafito-0.8.0/tests/test_maintenance.py +135 -0
  223. pygrafito-0.8.0/tests/test_model.py +267 -0
  224. pygrafito-0.8.0/tests/test_naming_convention.py +102 -0
  225. pygrafito-0.8.0/tests/test_package.py +120 -0
  226. pygrafito-0.8.0/tests/test_query_integration.py +237 -0
  227. pygrafito-0.8.0/tests/test_read_only.py +134 -0
  228. pygrafito-0.8.0/tests/test_readme.py +41 -0
  229. pygrafito-0.8.0/tests/test_transaction.py +418 -0
  230. pygrafito-0.8.0/tests/test_traversal_reads.py +227 -0
@@ -0,0 +1,98 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ quality:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Check out
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.14"
21
+
22
+ - name: Set up uv
23
+ uses: astral-sh/setup-uv@v6
24
+ with:
25
+ enable-cache: true
26
+
27
+ - name: Install Hatch
28
+ run: uv tool install hatch
29
+
30
+ - name: Add Hatch to PATH
31
+ run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"
32
+
33
+ - name: Cache Hatch environments
34
+ uses: actions/cache@v4
35
+ with:
36
+ path: |
37
+ ~/.cache/uv
38
+ ~/.local/share/hatch
39
+ key: hatch-${{ runner.os }}-${{ hashFiles('pyproject.toml') }}
40
+
41
+ - name: Check
42
+ run: hatch check
43
+
44
+ - name: Test
45
+ run: hatch test
46
+
47
+ package:
48
+ needs: quality
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - name: Check out
52
+ uses: actions/checkout@v4
53
+
54
+ - name: Set up Python
55
+ uses: actions/setup-python@v5
56
+ with:
57
+ python-version: "3.14"
58
+
59
+ - name: Set up uv
60
+ uses: astral-sh/setup-uv@v6
61
+ with:
62
+ enable-cache: true
63
+
64
+ - name: Build distributions
65
+ run: uv build
66
+
67
+ - name: Install wheel
68
+ run: |
69
+ uv venv .wheel-smoke
70
+ uv pip install --python .wheel-smoke/bin/python dist/*.whl
71
+
72
+ - name: Smoke test installed wheel
73
+ run: |
74
+ .wheel-smoke/bin/python - <<'PY'
75
+ from pygrafito import Graph
76
+
77
+ with Graph.open(":memory:") as graph:
78
+ node = graph.add_node("Program", designation="Tron")
79
+ assert graph.node(node.id)["designation"] == "Tron"
80
+ PY
81
+
82
+ - name: Smoke test the installed command
83
+ run: |
84
+ .wheel-smoke/bin/pygrafito --help
85
+ .wheel-smoke/bin/python -m pygrafito --help
86
+
87
+ - name: Verify wheel contents
88
+ run: |
89
+ python - <<'PY'
90
+ import glob
91
+ import zipfile
92
+
93
+ wheel = glob.glob("dist/*.whl")[0]
94
+ with zipfile.ZipFile(wheel) as archive:
95
+ names = set(archive.namelist())
96
+ assert any(name.endswith("py.typed") for name in names), names
97
+ assert any(name.endswith("LICENSE.txt") for name in names), names
98
+ PY
@@ -0,0 +1,70 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: pages-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Check out
22
+ uses: actions/checkout@v4
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.14"
28
+
29
+ - name: Set up uv
30
+ uses: astral-sh/setup-uv@v6
31
+ with:
32
+ enable-cache: true
33
+
34
+ - name: Install Hatch
35
+ run: uv tool install hatch
36
+
37
+ - name: Add Hatch to PATH
38
+ run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"
39
+
40
+ - name: Cache Hatch environments
41
+ uses: actions/cache@v4
42
+ with:
43
+ path: |
44
+ ~/.cache/uv
45
+ ~/.local/share/hatch
46
+ key: docs-${{ runner.os }}-${{ hashFiles('pyproject.toml') }}
47
+
48
+ - name: Build documentation
49
+ run: hatch run docs:build
50
+
51
+ - name: Configure Pages
52
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
53
+ uses: actions/configure-pages@v5
54
+
55
+ - name: Upload Pages artifact
56
+ uses: actions/upload-pages-artifact@v3
57
+ with:
58
+ path: docs/_build/html
59
+
60
+ deploy:
61
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
62
+ needs: build
63
+ runs-on: ubuntu-latest
64
+ environment:
65
+ name: github-pages
66
+ url: ${{ steps.deployment.outputs.page_url }}
67
+ steps:
68
+ - name: Deploy to GitHub Pages
69
+ id: deployment
70
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,88 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Check out
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.14"
21
+
22
+ - name: Set up uv
23
+ uses: astral-sh/setup-uv@v6
24
+ with:
25
+ enable-cache: true
26
+
27
+ - name: Install Hatch
28
+ run: uv tool install hatch
29
+
30
+ - name: Add Hatch to PATH
31
+ run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"
32
+
33
+ - name: Cache Hatch environments
34
+ uses: actions/cache@v4
35
+ with:
36
+ path: |
37
+ ~/.cache/uv
38
+ ~/.local/share/hatch
39
+ key: release-${{ runner.os }}-${{ hashFiles('pyproject.toml') }}
40
+
41
+ - name: Check
42
+ run: hatch check
43
+
44
+ - name: Test
45
+ run: hatch test
46
+
47
+ - name: Verify tag matches package version
48
+ run: |
49
+ python - <<'PY'
50
+ import os
51
+ import pathlib
52
+ import re
53
+
54
+ tag = os.environ["GITHUB_REF_NAME"]
55
+ about = pathlib.Path("src/pygrafito/__about__.py").read_text()
56
+ match = re.search(r'__version__ = "([^"]+)"', about)
57
+ assert match is not None, "no __version__ in __about__.py"
58
+ expected = f"v{match.group(1)}"
59
+ assert tag == expected, f"tag {tag!r} does not match version {expected!r}"
60
+ PY
61
+
62
+ - name: Build distributions
63
+ run: uv build
64
+
65
+ - name: Check distributions
66
+ run: uvx twine check dist/*
67
+
68
+ - name: Upload distributions
69
+ uses: actions/upload-artifact@v4
70
+ with:
71
+ name: dist
72
+ path: dist/
73
+
74
+ publish:
75
+ needs: build
76
+ runs-on: ubuntu-latest
77
+ environment: pypi
78
+ permissions:
79
+ id-token: write
80
+ steps:
81
+ - name: Download distributions
82
+ uses: actions/download-artifact@v4
83
+ with:
84
+ name: dist
85
+ path: dist/
86
+
87
+ - name: Publish to PyPI
88
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,220 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ *.lcov
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ # Pipfile.lock
97
+
98
+ # uv
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ # uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ # poetry.lock
110
+ # poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ # pdm.lock
117
+ # pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ # pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi/*
127
+ !.pixi/config.toml
128
+
129
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
130
+ __pypackages__/
131
+
132
+ # Celery stuff
133
+ celerybeat-schedule*
134
+ celerybeat.pid
135
+
136
+ # Redis
137
+ *.rdb
138
+ *.aof
139
+ *.pid
140
+
141
+ # RabbitMQ
142
+ mnesia/
143
+ rabbitmq/
144
+ rabbitmq-data/
145
+
146
+ # ActiveMQ
147
+ activemq-data/
148
+
149
+ # SageMath parsed files
150
+ *.sage.py
151
+
152
+ # Environments
153
+ .env
154
+ .envrc
155
+ .venv
156
+ env/
157
+ venv/
158
+ ENV/
159
+ env.bak/
160
+ venv.bak/
161
+
162
+ # Spyder project settings
163
+ .spyderproject
164
+ .spyproject
165
+
166
+ # Rope project settings
167
+ .ropeproject
168
+
169
+ # mkdocs/Zensical documentation
170
+ /site
171
+
172
+ # mypy
173
+ .mypy_cache/
174
+ .dmypy.json
175
+ dmypy.json
176
+
177
+ # Pyre type checker
178
+ .pyre/
179
+
180
+ # pytype static type analyzer
181
+ .pytype/
182
+
183
+ # Cython debug symbols
184
+ cython_debug/
185
+
186
+ # PyCharm
187
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
188
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
189
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
190
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
191
+ # .idea/
192
+
193
+ # Abstra
194
+ # Abstra is an AI-powered process automation framework.
195
+ # Ignore directories containing user credentials, local state, and settings.
196
+ # Learn more at https://abstra.io/docs
197
+ .abstra/
198
+
199
+ # Visual Studio Code
200
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
201
+ # can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
202
+ # and can be added to the global gitignore or merged into this file. However, if you prefer, you
203
+ # could uncomment the following to ignore the entire vscode folder
204
+ # .vscode/
205
+ # Temporary file for partial code execution
206
+ tempCodeRunnerFile.py
207
+
208
+ # Ruff stuff:
209
+ .ruff_cache/
210
+
211
+ # PyPI configuration file
212
+ .pypirc
213
+
214
+ # Marimo
215
+ marimo/_static/
216
+ marimo/_lsp/
217
+ __marimo__/
218
+
219
+ # Streamlit
220
+ .streamlit/secrets.toml
@@ -0,0 +1,199 @@
1
+ ---
2
+ description: "Implement tasks from an OpenSpec change (Experimental)"
3
+ ---
4
+
5
+ Implement tasks from an OpenSpec change.
6
+
7
+ **Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store <id>` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`, `schemas`, `view`). Once selected, treat `--store <id>` as sticky for the rest of the workflow. Every unscoped example of those commands below is shorthand: before running it, append the flag. For example, run `openspec status --change "<name>" --json --store "<id>"`, not the unscoped form shown below. Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root.
8
+
9
+ **Project check:** These steps expect a project that already uses OpenSpec. Before the first step that writes anything (`new change`, `archive`, `sync specs`, or authoring an artifact file), confirm the project has a root: run `openspec list --json` (with `--store <id>` when a store is selected, since the store is then the root) and read `root`. A root object means the project is set up. `"root": null` means it is not - there is no `openspec/` directory here, and a write such as `openspec new change` would create one as a side effect. The command also exits non-zero, which is that answer rather than a broken CLI, so read the JSON instead of retrying or working around it.
10
+
11
+ One `"root": null` is not about setup: when a `status` error message starts with `Declared in` or `Invalid store declaration in` and names this project's `openspec/config.yaml` (or `config.yml`), the project does use OpenSpec through a store it declares, which this machine cannot resolve (the store is not registered, or the `store:` line is malformed). Do not treat it as uninitialized and skip the branches below: stop before writing and show the user that error's `message` and `fix`.
12
+
13
+ Otherwise, with no root, what happens next depends on how this workflow was reached:
14
+
15
+ - **Auto-selected**: you chose this workflow yourself, without the user naming OpenSpec, naming this skill, or running its slash command. Stop using OpenSpec and answer the request normally, as you would with no OpenSpec installed. Do not ask them to set anything up and do not mention OpenSpec setup.
16
+ - **Explicit OpenSpec request**: the user named OpenSpec, named this skill, or ran its slash command. Stop before writing and ask how to proceed: set this project up (`openspec init`), target a store they already have (`--store <id>`), or continue without OpenSpec for this request. Wait for their answer.
17
+
18
+ In both branches, never create the root as a side effect: do not run `openspec init` until the user asks for it, do not hand-create `openspec/` files, and do not let a command create it.
19
+
20
+ **Input**: Optionally specify a change name (e.g., `/opsx-apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
21
+ **Provided arguments**: $ARGUMENTS
22
+
23
+ **Steps**
24
+
25
+ 1. **Select the change**
26
+
27
+ If a name is provided, use it. Otherwise:
28
+ - Infer from conversation context if the user mentioned a change
29
+ - Auto-select if only one active change exists
30
+ - If ambiguous, run `openspec list --json` to get available changes and ask the user to select one
31
+
32
+ Always announce: "Using change: <name>" and how to override (e.g., `/opsx-apply <other>`).
33
+
34
+ 2. **Check status to understand the schema**
35
+ ```bash
36
+ openspec status --change "<name>" --json
37
+ ```
38
+ Parse the JSON to understand:
39
+ - `schemaName`: The workflow being used (e.g., "spec-driven")
40
+ - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints
41
+ - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
42
+
43
+ 3. **Get apply instructions**
44
+
45
+ ```bash
46
+ openspec instructions apply --change "<name>" --json
47
+ ```
48
+
49
+ This returns:
50
+ - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema - could be proposal/specs/design/tasks or spec/tests/implementation/docs)
51
+ - Progress (total, complete, remaining)
52
+ - Task list with status, source path, and source line
53
+ - Dynamic instruction based on current state
54
+ - Optional `context`: current required project instruction input from the selected root
55
+ - Optional `operationGuidance`: current advisory guidance for apply
56
+ - `missingArtifacts` (when present): required artifact ids with no output
57
+
58
+ **Handle states:**
59
+ - If `state: "blocked"`: show the message and pause implementation.
60
+ - If `missingArtifacts` is non-empty: suggest completing the missing artifacts. Run `openspec status --change "<name>" --json`, select the next `ready` artifact (not `skipped` or `blocked`), and use `openspec instructions "<artifact-id>" --change "<name>" --json` for its rules and template. Keep the selected `--store <id>` on both commands.
61
+ - Otherwise, follow the CLI instruction to create or repair the schema-configured tracking file from existing planning artifacts. Do not assume another artifact is ready or start implementation while blocked.
62
+ - If `state: "all_done"`: report that all tracked tasks are complete and suggest review or verification as appropriate before archiving
63
+ - Otherwise: proceed to implementation
64
+
65
+ Treat `context` as a required prompt-level input. Read and consider it, and
66
+ apply relevant project facts, conventions, and constraints while implementing.
67
+ Treat `operationGuidance` as optional additive advice. Read and consider every
68
+ entry, and follow entries that are applicable and compatible with the built-in
69
+ workflow.
70
+
71
+ Keep both fields separate from CLI-returned state, missing artifacts, tasks,
72
+ progress, `contextFiles`, and the built-in `instruction`. They are not
73
+ evidence of task completion, do not replace the built-in instruction, and do
74
+ not permit bypassing a blocked state. If context conflicts with the built-in
75
+ instruction, an explicit user choice, or a CLI-controlled value, report the
76
+ conflict and preserve the controlling value. If guidance is inapplicable or
77
+ conflicts with those controlling inputs, do not follow it and explain why.
78
+ These are prompt-level behavior contracts, not enforceable checks.
79
+
80
+ 4. **Read context files**
81
+
82
+ Read every file path listed under `contextFiles` from the apply instructions output.
83
+ The files depend on the schema being used:
84
+ - **spec-driven**: proposal, specs, design, tasks
85
+ - Other schemas: follow the contextFiles from CLI output
86
+
87
+ Do not copy `context` or `operationGuidance` verbatim into implementation
88
+ files or planning artifacts unless the user separately asks for that content.
89
+
90
+ 5. **Show current progress**
91
+
92
+ Display:
93
+ - Schema being used
94
+ - Progress: "N/M tasks complete"
95
+ - Remaining tasks overview
96
+ - Dynamic instruction from CLI
97
+
98
+ 6. **Implement tasks (loop until done or blocked)**
99
+
100
+ For each pending task:
101
+ - Show which task is being worked on
102
+ - Make the code changes required
103
+ - Keep changes minimal and focused
104
+ - Before editing, confirm the checkbox at the returned `sourcePath` and `line` still matches the task description; if it does not, rerun the apply instructions and use the refreshed location
105
+ - Mark the task complete at its returned `sourcePath` and `line`: `- [ ]` → `- [x]`
106
+ - Rerun the apply instructions and confirm that task is now done and progress changed
107
+ - Continue to next task
108
+
109
+ **Pause if:**
110
+ - Task is unclear → ask for clarification
111
+ - Implementation reveals a design issue → suggest updating artifacts
112
+ - A task needs work beyond what the spec and tasks describe, or you are tempted to drop, narrow, defer, or accept exceptions to specified behavior to make it fit → surface the added scope and ask; do not absorb it silently
113
+ - Error or blocker encountered → report and wait for guidance
114
+ - User interrupts
115
+
116
+ 7. **On completion or pause, show status**
117
+
118
+ Display:
119
+ - Tasks completed this session
120
+ - Overall progress: "N/M tasks complete"
121
+ - If all done: report that tracked tasks are complete and suggest review or verification as appropriate before archiving
122
+ - If paused: explain why and wait for guidance
123
+
124
+ **Output During Implementation**
125
+
126
+ ```
127
+ ## Implementing: <change-name> (schema: <schema-name>)
128
+
129
+ Working on task 3/7: <task description>
130
+ [...implementation happening...]
131
+ ✓ Task complete
132
+
133
+ Working on task 4/7: <task description>
134
+ [...implementation happening...]
135
+ ✓ Task complete
136
+ ```
137
+
138
+ **Output On Completion**
139
+
140
+ ```
141
+ ## Implementation Complete
142
+
143
+ **Change:** <change-name>
144
+ **Schema:** <schema-name>
145
+ **Progress:** 7/7 tasks complete ✓
146
+
147
+ ### Completed This Session
148
+ - [x] Task 1
149
+ - [x] Task 2
150
+ ...
151
+
152
+ All tracked tasks are complete. Review or verify the change as appropriate
153
+ before archiving. You can archive this change with `/opsx-archive`.
154
+ ```
155
+
156
+ **Output On Pause (Issue Encountered)**
157
+
158
+ ```
159
+ ## Implementation Paused
160
+
161
+ **Change:** <change-name>
162
+ **Schema:** <schema-name>
163
+ **Progress:** 4/7 tasks complete
164
+
165
+ ### Issue Encountered
166
+ <description of the issue>
167
+
168
+ **Options:**
169
+ 1. <option 1>
170
+ 2. <option 2>
171
+ 3. Other approach
172
+
173
+ What would you like to do?
174
+ ```
175
+
176
+ **Guardrails**
177
+ - Keep going through tasks until done or blocked
178
+ - Always read context files before starting (from the apply instructions output)
179
+ - If task is ambiguous, pause and ask before implementing
180
+ - If implementation reveals issues, pause and suggest artifact updates
181
+ - Keep code changes minimal and scoped to each task
182
+ - Update task checkbox immediately after completing each task
183
+ - Pause on errors, blockers, or unclear requirements - don't guess
184
+ - When a task needs work beyond what the spec describes, surface the added scope and pause - never silently narrow, defer, or simplify away specified behavior
185
+ - Only mark a task `- [x]` when its specified behavior is fully implemented, not when it is partially done or deferred
186
+ - Use contextFiles from CLI output, don't assume specific file names
187
+ - Use each task's sourcePath and line to update its exact checkbox
188
+ - Do not use context or operation guidance as proof that a task is complete
189
+ - Apply relevant project context; report conflicts with controlling workflow inputs
190
+ - Consider every guidance entry; explain any inapplicable or conflicting advice
191
+ - Do not copy runtime context or operation guidance into implementation files or planning artifacts
192
+ - Preserve CLI-controlled blocked/ready/all-done behavior and completion criteria
193
+
194
+ **Fluid Workflow Integration**
195
+
196
+ This skill supports the "actions on a change" model:
197
+
198
+ - **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
199
+ - **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly