graphitect 0.2.0__py3-none-any.whl

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 (336) hide show
  1. graphify/__init__.py +30 -0
  2. graphify/__main__.py +757 -0
  3. graphify/_minhash.py +107 -0
  4. graphify/affected.py +318 -0
  5. graphify/always_on/agents-md.md +12 -0
  6. graphify/always_on/antigravity-rules.md +14 -0
  7. graphify/always_on/claude-md.md +9 -0
  8. graphify/always_on/gemini-md.md +9 -0
  9. graphify/always_on/kiro-steering.md +5 -0
  10. graphify/always_on/vscode-instructions.md +17 -0
  11. graphify/analyze.py +769 -0
  12. graphify/benchmark.py +152 -0
  13. graphify/build.py +2300 -0
  14. graphify/cache.py +1746 -0
  15. graphify/callflow_html.py +2051 -0
  16. graphify/cargo_introspect.py +109 -0
  17. graphify/cli.py +4745 -0
  18. graphify/cluster.py +409 -0
  19. graphify/command-kilo.md +15 -0
  20. graphify/cross_repo_calls.py +216 -0
  21. graphify/cross_repo_types.py +75 -0
  22. graphify/csharp_dispatch.py +154 -0
  23. graphify/dedup.py +1213 -0
  24. graphify/detect.py +2566 -0
  25. graphify/diagnostics.py +406 -0
  26. graphify/export.py +1349 -0
  27. graphify/exporters/__init__.py +1 -0
  28. graphify/exporters/base.py +14 -0
  29. graphify/exporters/graphdb.py +173 -0
  30. graphify/exporters/html.py +637 -0
  31. graphify/extract.py +7856 -0
  32. graphify/extractors/MIGRATION.md +107 -0
  33. graphify/extractors/__init__.py +66 -0
  34. graphify/extractors/apex.py +215 -0
  35. graphify/extractors/base.py +85 -0
  36. graphify/extractors/bash.py +579 -0
  37. graphify/extractors/blade.py +53 -0
  38. graphify/extractors/commonlisp.py +540 -0
  39. graphify/extractors/csharp.py +448 -0
  40. graphify/extractors/dart.py +564 -0
  41. graphify/extractors/dm.py +494 -0
  42. graphify/extractors/elixir.py +241 -0
  43. graphify/extractors/engine.py +6509 -0
  44. graphify/extractors/fortran.py +311 -0
  45. graphify/extractors/go.py +527 -0
  46. graphify/extractors/json_config.py +240 -0
  47. graphify/extractors/julia.py +289 -0
  48. graphify/extractors/markdown.py +408 -0
  49. graphify/extractors/models.py +131 -0
  50. graphify/extractors/objc.py +566 -0
  51. graphify/extractors/ocaml.py +289 -0
  52. graphify/extractors/pascal.py +688 -0
  53. graphify/extractors/pascal_forms.py +196 -0
  54. graphify/extractors/powershell.py +522 -0
  55. graphify/extractors/razor.py +192 -0
  56. graphify/extractors/resolution.py +3584 -0
  57. graphify/extractors/robot.py +296 -0
  58. graphify/extractors/rust.py +470 -0
  59. graphify/extractors/sln.py +92 -0
  60. graphify/extractors/sql.py +720 -0
  61. graphify/extractors/terraform.py +181 -0
  62. graphify/extractors/verilog.py +329 -0
  63. graphify/extractors/zig.py +181 -0
  64. graphify/file_slice.py +246 -0
  65. graphify/global_graph.py +194 -0
  66. graphify/google_workspace.py +237 -0
  67. graphify/hooks.py +933 -0
  68. graphify/ids.py +93 -0
  69. graphify/ingest.py +358 -0
  70. graphify/install.py +2366 -0
  71. graphify/llm.py +3544 -0
  72. graphify/manifest.py +4 -0
  73. graphify/manifest_ingest.py +311 -0
  74. graphify/mcp_ingest.py +386 -0
  75. graphify/multigraph_compat.py +212 -0
  76. graphify/pascal_resolution.py +129 -0
  77. graphify/paths.py +436 -0
  78. graphify/pg_introspect.py +165 -0
  79. graphify/prs.py +770 -0
  80. graphify/querylog.py +80 -0
  81. graphify/reflect.py +882 -0
  82. graphify/report.py +346 -0
  83. graphify/resolver_registry.py +85 -0
  84. graphify/ruby_resolution.py +242 -0
  85. graphify/scip_ingest.py +363 -0
  86. graphify/security.py +460 -0
  87. graphify/semantic_cleanup.py +336 -0
  88. graphify/serve.py +2608 -0
  89. graphify/skill-agents.md +710 -0
  90. graphify/skill-aider.md +1283 -0
  91. graphify/skill-amp.md +710 -0
  92. graphify/skill-claw.md +713 -0
  93. graphify/skill-codex.md +710 -0
  94. graphify/skill-copilot.md +713 -0
  95. graphify/skill-devin.md +1410 -0
  96. graphify/skill-droid.md +710 -0
  97. graphify/skill-kilo.md +722 -0
  98. graphify/skill-kiro.md +713 -0
  99. graphify/skill-opencode.md +705 -0
  100. graphify/skill-pi.md +713 -0
  101. graphify/skill-trae.md +711 -0
  102. graphify/skill-vscode.md +709 -0
  103. graphify/skill-windows.md +755 -0
  104. graphify/skill.md +713 -0
  105. graphify/skills/agents/references/add-watch.md +56 -0
  106. graphify/skills/agents/references/exports.md +87 -0
  107. graphify/skills/agents/references/extraction-spec.md +70 -0
  108. graphify/skills/agents/references/github-and-merge.md +46 -0
  109. graphify/skills/agents/references/hooks.md +33 -0
  110. graphify/skills/agents/references/query.md +311 -0
  111. graphify/skills/agents/references/transcribe.md +52 -0
  112. graphify/skills/agents/references/update.md +210 -0
  113. graphify/skills/amp/references/add-watch.md +56 -0
  114. graphify/skills/amp/references/exports.md +87 -0
  115. graphify/skills/amp/references/extraction-spec.md +70 -0
  116. graphify/skills/amp/references/github-and-merge.md +46 -0
  117. graphify/skills/amp/references/hooks.md +33 -0
  118. graphify/skills/amp/references/query.md +311 -0
  119. graphify/skills/amp/references/transcribe.md +52 -0
  120. graphify/skills/amp/references/update.md +210 -0
  121. graphify/skills/claude/references/add-watch.md +56 -0
  122. graphify/skills/claude/references/exports.md +87 -0
  123. graphify/skills/claude/references/extraction-spec.md +70 -0
  124. graphify/skills/claude/references/github-and-merge.md +46 -0
  125. graphify/skills/claude/references/hooks.md +33 -0
  126. graphify/skills/claude/references/query.md +311 -0
  127. graphify/skills/claude/references/transcribe.md +52 -0
  128. graphify/skills/claude/references/update.md +210 -0
  129. graphify/skills/claw/references/add-watch.md +56 -0
  130. graphify/skills/claw/references/exports.md +87 -0
  131. graphify/skills/claw/references/extraction-spec.md +31 -0
  132. graphify/skills/claw/references/github-and-merge.md +46 -0
  133. graphify/skills/claw/references/hooks.md +33 -0
  134. graphify/skills/claw/references/query.md +311 -0
  135. graphify/skills/claw/references/transcribe.md +52 -0
  136. graphify/skills/claw/references/update.md +210 -0
  137. graphify/skills/codex/references/add-watch.md +56 -0
  138. graphify/skills/codex/references/exports.md +87 -0
  139. graphify/skills/codex/references/extraction-spec.md +31 -0
  140. graphify/skills/codex/references/github-and-merge.md +46 -0
  141. graphify/skills/codex/references/hooks.md +33 -0
  142. graphify/skills/codex/references/query.md +311 -0
  143. graphify/skills/codex/references/transcribe.md +52 -0
  144. graphify/skills/codex/references/update.md +210 -0
  145. graphify/skills/copilot/references/add-watch.md +56 -0
  146. graphify/skills/copilot/references/exports.md +87 -0
  147. graphify/skills/copilot/references/extraction-spec.md +70 -0
  148. graphify/skills/copilot/references/github-and-merge.md +46 -0
  149. graphify/skills/copilot/references/hooks.md +33 -0
  150. graphify/skills/copilot/references/query.md +311 -0
  151. graphify/skills/copilot/references/transcribe.md +52 -0
  152. graphify/skills/copilot/references/update.md +210 -0
  153. graphify/skills/droid/references/add-watch.md +56 -0
  154. graphify/skills/droid/references/exports.md +87 -0
  155. graphify/skills/droid/references/extraction-spec.md +70 -0
  156. graphify/skills/droid/references/github-and-merge.md +46 -0
  157. graphify/skills/droid/references/hooks.md +33 -0
  158. graphify/skills/droid/references/query.md +311 -0
  159. graphify/skills/droid/references/transcribe.md +52 -0
  160. graphify/skills/droid/references/update.md +210 -0
  161. graphify/skills/kilo/references/add-watch.md +56 -0
  162. graphify/skills/kilo/references/exports.md +87 -0
  163. graphify/skills/kilo/references/extraction-spec.md +70 -0
  164. graphify/skills/kilo/references/github-and-merge.md +46 -0
  165. graphify/skills/kilo/references/hooks.md +33 -0
  166. graphify/skills/kilo/references/query.md +311 -0
  167. graphify/skills/kilo/references/transcribe.md +52 -0
  168. graphify/skills/kilo/references/update.md +210 -0
  169. graphify/skills/kiro/references/add-watch.md +56 -0
  170. graphify/skills/kiro/references/exports.md +87 -0
  171. graphify/skills/kiro/references/extraction-spec.md +31 -0
  172. graphify/skills/kiro/references/github-and-merge.md +46 -0
  173. graphify/skills/kiro/references/hooks.md +33 -0
  174. graphify/skills/kiro/references/query.md +311 -0
  175. graphify/skills/kiro/references/transcribe.md +52 -0
  176. graphify/skills/kiro/references/update.md +210 -0
  177. graphify/skills/opencode/references/add-watch.md +56 -0
  178. graphify/skills/opencode/references/exports.md +87 -0
  179. graphify/skills/opencode/references/extraction-spec.md +70 -0
  180. graphify/skills/opencode/references/github-and-merge.md +46 -0
  181. graphify/skills/opencode/references/hooks.md +33 -0
  182. graphify/skills/opencode/references/query.md +311 -0
  183. graphify/skills/opencode/references/transcribe.md +52 -0
  184. graphify/skills/opencode/references/update.md +210 -0
  185. graphify/skills/pi/references/add-watch.md +56 -0
  186. graphify/skills/pi/references/exports.md +87 -0
  187. graphify/skills/pi/references/extraction-spec.md +31 -0
  188. graphify/skills/pi/references/github-and-merge.md +46 -0
  189. graphify/skills/pi/references/hooks.md +33 -0
  190. graphify/skills/pi/references/query.md +311 -0
  191. graphify/skills/pi/references/transcribe.md +52 -0
  192. graphify/skills/pi/references/update.md +210 -0
  193. graphify/skills/trae/references/add-watch.md +56 -0
  194. graphify/skills/trae/references/exports.md +87 -0
  195. graphify/skills/trae/references/extraction-spec.md +70 -0
  196. graphify/skills/trae/references/github-and-merge.md +46 -0
  197. graphify/skills/trae/references/hooks.md +35 -0
  198. graphify/skills/trae/references/query.md +311 -0
  199. graphify/skills/trae/references/transcribe.md +52 -0
  200. graphify/skills/trae/references/update.md +210 -0
  201. graphify/skills/vscode/references/add-watch.md +56 -0
  202. graphify/skills/vscode/references/exports.md +87 -0
  203. graphify/skills/vscode/references/extraction-spec.md +70 -0
  204. graphify/skills/vscode/references/github-and-merge.md +46 -0
  205. graphify/skills/vscode/references/hooks.md +33 -0
  206. graphify/skills/vscode/references/query.md +311 -0
  207. graphify/skills/vscode/references/transcribe.md +52 -0
  208. graphify/skills/vscode/references/update.md +210 -0
  209. graphify/skills/windows/references/add-watch.md +56 -0
  210. graphify/skills/windows/references/exports.md +87 -0
  211. graphify/skills/windows/references/extraction-spec.md +70 -0
  212. graphify/skills/windows/references/github-and-merge.md +46 -0
  213. graphify/skills/windows/references/hooks.md +33 -0
  214. graphify/skills/windows/references/query.md +311 -0
  215. graphify/skills/windows/references/transcribe.md +52 -0
  216. graphify/skills/windows/references/update.md +210 -0
  217. graphify/symbol_resolution.py +556 -0
  218. graphify/transcribe.py +186 -0
  219. graphify/tree_html.py +603 -0
  220. graphify/validate.py +95 -0
  221. graphify/watch.py +2280 -0
  222. graphify/wiki.py +405 -0
  223. graphitect/__init__.py +28 -0
  224. graphitect/__main__.py +4 -0
  225. graphitect/_vendor/__init__.py +2 -0
  226. graphitect/_vendor/archify/LICENSE +22 -0
  227. graphitect/_vendor/archify/SKILL.md +137 -0
  228. graphitect/_vendor/archify/THIRD_PARTY_NOTICES.md +69 -0
  229. graphitect/_vendor/archify/assets/JetBrainsMono-OFL.txt +93 -0
  230. graphitect/_vendor/archify/assets/template.html +14935 -0
  231. graphitect/_vendor/archify/bin/archify.mjs +2091 -0
  232. graphitect/_vendor/archify/bin/open-artifact.mjs +86 -0
  233. graphitect/_vendor/archify/bin/preview.mjs +653 -0
  234. graphitect/_vendor/archify/bin/visual-check.mjs +829 -0
  235. graphitect/_vendor/archify/brand-marks/README.md +31 -0
  236. graphitect/_vendor/archify/brand-marks/catalog.json +131 -0
  237. graphitect/_vendor/archify/delta/architecture-delta.mjs +1221 -0
  238. graphitect/_vendor/archify/examples/agent-run.lifecycle.json +60 -0
  239. graphitect/_vendor/archify/examples/agent-tool-call.workflow.json +94 -0
  240. graphitect/_vendor/archify/examples/async-job-roundtrip.sequence.json +61 -0
  241. graphitect/_vendor/archify/examples/brand-aware-delivery.architecture.json +47 -0
  242. graphitect/_vendor/archify/examples/cache-miss-request.sequence.json +82 -0
  243. graphitect/_vendor/archify/examples/checkout-platform.base.architecture.json +31 -0
  244. graphitect/_vendor/archify/examples/checkout-platform.head.architecture.json +31 -0
  245. graphitect/_vendor/archify/examples/dataflow-product-analytics.html +15045 -0
  246. graphitect/_vendor/archify/examples/deployment-release.lifecycle.json +49 -0
  247. graphitect/_vendor/archify/examples/event-stream.dataflow.json +57 -0
  248. graphitect/_vendor/archify/examples/incident-response.workflow.json +64 -0
  249. graphitect/_vendor/archify/examples/lifecycle-agent-run.html +14980 -0
  250. graphitect/_vendor/archify/examples/product-analytics.dataflow.json +76 -0
  251. graphitect/_vendor/archify/examples/production-deployment.architecture.json +71 -0
  252. graphitect/_vendor/archify/examples/release-delivery.workflow.json +62 -0
  253. graphitect/_vendor/archify/examples/sequence-cache-miss-request.html +15060 -0
  254. graphitect/_vendor/archify/examples/web-app-rendered.html +15009 -0
  255. graphitect/_vendor/archify/examples/web-app.architecture.json +46 -0
  256. graphitect/_vendor/archify/examples/workflow-agent-tool-call-rendered.html +15051 -0
  257. graphitect/_vendor/archify/migrations/workflow-v2.mjs +279 -0
  258. graphitect/_vendor/archify/package-lock.json +149 -0
  259. graphitect/_vendor/archify/package.json +39 -0
  260. graphitect/_vendor/archify/recipes/scenarios.mjs +391 -0
  261. graphitect/_vendor/archify/references/authoring-contract.md +243 -0
  262. graphitect/_vendor/archify/references/brand-marks.md +65 -0
  263. graphitect/_vendor/archify/references/delivery-contract.md +120 -0
  264. graphitect/_vendor/archify/references/viewer-runtime.md +45 -0
  265. graphitect/_vendor/archify/renderers/architecture/grid.mjs +62 -0
  266. graphitect/_vendor/archify/renderers/architecture/render-architecture.mjs +1078 -0
  267. graphitect/_vendor/archify/renderers/dataflow/README.md +104 -0
  268. graphitect/_vendor/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  269. graphitect/_vendor/archify/renderers/lifecycle/README.md +115 -0
  270. graphitect/_vendor/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  271. graphitect/_vendor/archify/renderers/sequence/README.md +114 -0
  272. graphitect/_vendor/archify/renderers/sequence/render-sequence.mjs +464 -0
  273. graphitect/_vendor/archify/renderers/shared/brand-marks.mjs +563 -0
  274. graphitect/_vendor/archify/renderers/shared/cli.mjs +218 -0
  275. graphitect/_vendor/archify/renderers/shared/desktop-readability.mjs +26 -0
  276. graphitect/_vendor/archify/renderers/shared/diagnostics.mjs +127 -0
  277. graphitect/_vendor/archify/renderers/shared/engineering-profiles.mjs +157 -0
  278. graphitect/_vendor/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  279. graphitect/_vendor/archify/renderers/shared/generated-validators.mjs +13 -0
  280. graphitect/_vendor/archify/renderers/shared/geometry.mjs +1423 -0
  281. graphitect/_vendor/archify/renderers/shared/i18n.mjs +595 -0
  282. graphitect/_vendor/archify/renderers/shared/layout-report.mjs +40 -0
  283. graphitect/_vendor/archify/renderers/shared/legend.mjs +217 -0
  284. graphitect/_vendor/archify/renderers/shared/output-path.mjs +340 -0
  285. graphitect/_vendor/archify/renderers/shared/repository-evidence.mjs +238 -0
  286. graphitect/_vendor/archify/renderers/shared/repository-location.mjs +58 -0
  287. graphitect/_vendor/archify/renderers/shared/text-fit.mjs +49 -0
  288. graphitect/_vendor/archify/renderers/shared/utils.mjs +232 -0
  289. graphitect/_vendor/archify/renderers/shared/validator.mjs +86 -0
  290. graphitect/_vendor/archify/renderers/workflow/README.md +223 -0
  291. graphitect/_vendor/archify/renderers/workflow/render-workflow.mjs +35 -0
  292. graphitect/_vendor/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  293. graphitect/_vendor/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  294. graphitect/_vendor/archify/schemas/README.md +211 -0
  295. graphitect/_vendor/archify/schemas/architecture.schema.json +178 -0
  296. graphitect/_vendor/archify/schemas/common.schema.json +115 -0
  297. graphitect/_vendor/archify/schemas/dataflow.schema.json +243 -0
  298. graphitect/_vendor/archify/schemas/lifecycle.schema.json +266 -0
  299. graphitect/_vendor/archify/schemas/sequence.schema.json +223 -0
  300. graphitect/_vendor/archify/schemas/workflow.schema.json +428 -0
  301. graphitect/_vendor/archify/scripts/check-render-output.mjs +836 -0
  302. graphitect/_vendor/archify/scripts/check-update.mjs +1667 -0
  303. graphitect/_vendor/archify/scripts/generate-brand-marks.mjs +141 -0
  304. graphitect/_vendor/archify/scripts/generate-validators.mjs +66 -0
  305. graphitect/_vendor/archify/scripts/render-examples.mjs +26 -0
  306. graphitect/_vendor/archify/scripts/update-contract.mjs +182 -0
  307. graphitect/_vendor/archify/skill-release.json +10 -0
  308. graphitect/cli.py +981 -0
  309. graphitect/deliver/__init__.py +5 -0
  310. graphitect/deliver/archify_adapter.py +1877 -0
  311. graphitect/deliver/archify_ir.py +160 -0
  312. graphitect/deliver/archify_repair.py +135 -0
  313. graphitect/deliver/doc_compiler.py +916 -0
  314. graphitect/ground/__init__.py +5 -0
  315. graphitect/ground/describe_source.py +27 -0
  316. graphitect/ground/fullread_source.py +56 -0
  317. graphitect/ground/graphify_source.py +107 -0
  318. graphitect/models.py +118 -0
  319. graphitect/skill/SKILL.md +80 -0
  320. graphitect/skill/agents/openai.yaml +4 -0
  321. graphitect/synthesize/__init__.py +5 -0
  322. graphitect/synthesize/engine.py +281 -0
  323. graphitect/synthesize/llm_backend.py +331 -0
  324. graphitect/synthesize/questions.py +139 -0
  325. graphitect/synthesize/rubric.py +104 -0
  326. graphitect-0.2.0.dist-info/METADATA +284 -0
  327. graphitect-0.2.0.dist-info/RECORD +336 -0
  328. graphitect-0.2.0.dist-info/WHEEL +5 -0
  329. graphitect-0.2.0.dist-info/entry_points.txt +2 -0
  330. graphitect-0.2.0.dist-info/licenses/LICENSE +21 -0
  331. graphitect-0.2.0.dist-info/licenses/LICENSE-ARCHIFY-MIT +22 -0
  332. graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-APACHE-2.0 +202 -0
  333. graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-MIT +21 -0
  334. graphitect-0.2.0.dist-info/licenses/NOTICE-ARCHIFY-THIRD-PARTY.md +69 -0
  335. graphitect-0.2.0.dist-info/licenses/NOTICE-GRAPHIFY +8 -0
  336. graphitect-0.2.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,5 @@
1
+ """Three grounding sources, picked per repo - plan.md §02."""
2
+
3
+ from . import describe_source, fullread_source, graphify_source
4
+
5
+ __all__ = ["describe_source", "fullread_source", "graphify_source"]
@@ -0,0 +1,27 @@
1
+ """Grounding via a plain-language description - fastest, no repo access
2
+ needed, weakest evidence (plan.md §02). Everything from this source is
3
+ inherently `inferred` (technically `user`-sourced but unverified against
4
+ code), since nothing here is checked against real code.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from ..models import Claim, Confidence, Evidence
10
+
11
+
12
+ def ground(description: str) -> list[Claim]:
13
+ """Wrap the user's own description as a single unverified claim per
14
+ paragraph. A real implementation would still run this through an LLM to
15
+ extract structured claims; this stub keeps the boundary explicit: nothing
16
+ from Describe-it is ever `confirmed` by construction, since there's
17
+ nothing to check it against.
18
+ """
19
+ paragraphs = [p.strip() for p in description.split("\n\n") if p.strip()]
20
+ return [
21
+ Claim(
22
+ text=p,
23
+ confidence=Confidence.INFERRED,
24
+ cites=[Evidence(source="user", note="Describe-it mode - not verified against code")],
25
+ )
26
+ for p in paragraphs
27
+ ]
@@ -0,0 +1,56 @@
1
+ """Grounding via a full LLM read of the repo - README, git log, commit
2
+ messages, existing docs (plan.md §02). Where rationale actually comes from:
3
+ Graphify can tell you two modules are connected, not why Redis sits between
4
+ them.
5
+
6
+ This is the one grounding source that fundamentally needs an LLM, which is
7
+ also the one place the skill and CLI surfaces genuinely diverge in
8
+ capability (plan.md §05):
9
+ - as a skill, the host IS the LLM - `read_fn` dispatches the host's own
10
+ subagents (e.g. Claude Code's Agent tool), same pattern Graphify itself
11
+ uses for semantic extraction when no GEMINI_API_KEY is set.
12
+ - standalone, `read_fn` must be backed by the caller's own
13
+ ANTHROPIC_API_KEY / GEMINI_API_KEY - there's no host LLM to borrow.
14
+
15
+ Nothing here performs the read itself; ReadFn is the seam both surfaces
16
+ implement differently while everything downstream (rubric, questions,
17
+ GroundedUnderstanding) stays identical.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from pathlib import Path
23
+ from typing import Protocol
24
+
25
+ from ..models import Claim
26
+
27
+
28
+ class ReadFn(Protocol):
29
+ """One full-read pass over a repo, returning extracted claims.
30
+
31
+ Implementations differ by surface (host subagent dispatch vs. a direct
32
+ API call) but must return the same shape: raw claims with confidence
33
+ already assessed against what was actually found, ready for the rubric
34
+ in graphitect.synthesize.rubric to mine further or queue a question.
35
+ """
36
+
37
+ def __call__(self, repo_path: Path, sources: list[Path]) -> list[Claim]: ...
38
+
39
+
40
+ def default_sources(repo_path: Path) -> list[Path]:
41
+ """README, CHANGELOG, and any docs/specs - the rubric's own search order
42
+ (plan.md §03), collected once so both a skill subagent and a standalone
43
+ LLM call read the same files.
44
+ """
45
+ candidates = [
46
+ repo_path / "README.md",
47
+ repo_path / "CHANGELOG.md",
48
+ ]
49
+ docs_dir = repo_path / "docs"
50
+ if docs_dir.is_dir():
51
+ candidates.extend(sorted(docs_dir.rglob("*.md")))
52
+ return [p for p in candidates if p.exists()]
53
+
54
+
55
+ def ground(repo_path: Path, read_fn: ReadFn) -> list[Claim]:
56
+ return read_fn(repo_path, default_sources(repo_path))
@@ -0,0 +1,107 @@
1
+ """Grounding via Graphify's structure graph - most accurate, cheapest per
2
+ file, works offline (plan.md §02). Reuses an existing graphify-out/graph.json
3
+ if present; otherwise shells out to run graphify first.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import importlib.util
9
+ import json
10
+ import os
11
+ import shutil
12
+ import subprocess
13
+ import sys
14
+ from pathlib import Path
15
+
16
+
17
+ def ground(
18
+ repo_path: Path,
19
+ *,
20
+ graphify_bin: str | None = None,
21
+ force_rebuild: bool = False,
22
+ output_dir: Path | None = None,
23
+ ) -> dict:
24
+ """Return {"nodes": [...], "edges": [...], "communities": {...}} from
25
+ graphify's own graph.json export, running graphify first if needed.
26
+
27
+ Never overwrites an existing graphify-out/ blindly - always prefers
28
+ `graphify <path> --update` over a fresh build when a graph already
29
+ exists, learned the hard way running Phase 1 against a live repo
30
+ that already had its own Graphify setup (plan.md §06, Phase 1 risk).
31
+ """
32
+ graph_output = output_dir.resolve() if output_dir else repo_path / "graphify-out"
33
+ graph_json = graph_output / "graph.json"
34
+ bundled_spec = None
35
+ if graphify_bin:
36
+ bin_cmd = [graphify_bin]
37
+ elif (bundled_spec := importlib.util.find_spec("graphify")) is not None:
38
+ # Graphify ships inside the Graphitect wheel. Use the current Python
39
+ # interpreter so no separate `graphify` installation or PATH entry is
40
+ # required.
41
+ bin_cmd = [sys.executable, "-m", "graphify"]
42
+ else:
43
+ on_path = shutil.which("graphify")
44
+ bin_cmd = [on_path] if on_path else None
45
+
46
+ if not graph_json.exists() or force_rebuild:
47
+ if not bin_cmd:
48
+ raise FileNotFoundError(
49
+ "bundled Graphify runtime is missing and no existing "
50
+ "graphify-out/graph.json can be reused"
51
+ )
52
+ # Graphitect uses Graphify for deterministic source structure. README
53
+ # and docs are read by Graphitect's own optional LLM pass, so Graphify
54
+ # must never require a second API key just to build the mandatory
55
+ # no-LLM diagram.
56
+ cmd = [*bin_cmd, str(repo_path), "--code-only"]
57
+ if graph_json.exists():
58
+ cmd.append("--update") # incremental, safe - never a blind full rebuild
59
+ env = os.environ.copy()
60
+ env["GRAPHIFY_EMBEDDED"] = "1"
61
+ if bundled_spec is not None and getattr(bundled_spec, "origin", None):
62
+ # Editable/source installs may only expose Graphify because the
63
+ # checkout is the current directory. The analyzer runs with the
64
+ # target repository as cwd, so preserve the discovered package
65
+ # root for that child process. A normal wheel install already has
66
+ # it on sys.path; this is harmless there.
67
+ package_root = str(Path(bundled_spec.origin).resolve().parent.parent)
68
+ existing_pythonpath = env.get("PYTHONPATH")
69
+ env["PYTHONPATH"] = (
70
+ package_root + os.pathsep + existing_pythonpath
71
+ if existing_pythonpath
72
+ else package_root
73
+ )
74
+ if output_dir:
75
+ # The product-level `build` command uses a temporary Graphify
76
+ # directory so the report really is its only persistent output.
77
+ env["GRAPHIFY_OUT"] = str(graph_output)
78
+ subprocess.run(cmd, check=True, cwd=repo_path, env=env)
79
+
80
+ data = json.loads(graph_json.read_text(encoding="utf-8"))
81
+ return {
82
+ "nodes": data.get("nodes", []),
83
+ "edges": data.get("links", data.get("edges", [])), # graph.json uses networkx "links"
84
+ "communities": _labels_by_community(data),
85
+ # Plain-language community names, if a real graphify run produced
86
+ # them (graphify-out/.graphify_labels.json). Used to name aggregated
87
+ # diagram boxes ("MF Catalog Review Triage") instead of a bare
88
+ # "Community 42" when a large graph gets collapsed to community
89
+ # level - see archify_adapter._aggregate_by_community.
90
+ "community_labels": _read_community_labels(graph_output),
91
+ }
92
+
93
+
94
+ def _labels_by_community(graph_json_data: dict) -> dict[int, list[str]]:
95
+ by_community: dict[int, list[str]] = {}
96
+ for node in graph_json_data.get("nodes", []):
97
+ cid = node.get("community")
98
+ if cid is not None:
99
+ by_community.setdefault(cid, []).append(node["id"])
100
+ return by_community
101
+
102
+
103
+ def _read_community_labels(graph_output: Path) -> dict[str, str]:
104
+ labels_path = graph_output / ".graphify_labels.json"
105
+ if not labels_path.exists():
106
+ return {}
107
+ return json.loads(labels_path.read_text(encoding="utf-8"))
graphitect/models.py ADDED
@@ -0,0 +1,118 @@
1
+ """Shared model for graphitect - see plan.md sections 03/04.
2
+
3
+ One internal structure produced by Synthesize, mapped two ways downstream:
4
+ into archify's own typed IR for the diagram, and into a sourced doc outline
5
+ for the write-up. Every claim traces to evidence or is explicitly labeled a
6
+ guess - never presented as confident prose either way.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from enum import Enum
12
+ from typing import Literal
13
+
14
+ from pydantic import BaseModel, ConfigDict, Field
15
+
16
+
17
+ class Confidence(str, Enum):
18
+ CONFIRMED = "confirmed" # direct code fact, or the author said so
19
+ INFERRED = "inferred" # plausible - must be labeled as such
20
+
21
+
22
+ class Evidence(BaseModel):
23
+ source: Literal["code", "readme", "git_log", "docs", "user"]
24
+ file: str | None = None
25
+ line: int | None = None
26
+ note: str | None = None # e.g. commit message excerpt, or the user's own answer
27
+
28
+
29
+ class Claim(BaseModel):
30
+ text: str # "chose FastAPI for async support"
31
+ confidence: Confidence
32
+ cites: list[Evidence] = Field(default_factory=list)
33
+ # "descriptive" = a fact about a past decision, askable via the rubric.
34
+ # "prescriptive" = the tool's own recommendation/suggestion, never askable -
35
+ # asking "did you really mean this suggestion" doesn't make sense (plan.md §03).
36
+ kind: Literal["descriptive", "prescriptive"] = "descriptive"
37
+
38
+
39
+ class Tradeoff(BaseModel):
40
+ """A real pros/cons comparison for one architectural/technical decision -
41
+ what "Tradeoffs & alternatives considered" is actually for, beyond a
42
+ flat claim bullet (Naman's request, 12 Sep 2026, for a more in-depth,
43
+ explanatory doc). `decision`/`pros`/`cons` are full Claims - confidence
44
+ tag + citations, exactly like anything else in the doc - so a table row
45
+ can never quietly carry an unverified assertion the rest of the doc
46
+ wouldn't allow; engine.synthesize() re-verifies all three the same way
47
+ it verifies section.claims. `decision` may restate or elaborate a claim
48
+ already present in this section's own `claims` list - the flat list is
49
+ the quick-scan version, this is the detailed one.
50
+
51
+ Not currently wired into the interactive Q&A/pending-question flow
52
+ (scoped out deliberately - see plan.md): an inferred, unresolved
53
+ tradeoff still displays honestly labeled, it just isn't independently
54
+ askable via --answers the way a flat section.claims entry is.
55
+ """
56
+
57
+ decision: Claim
58
+ alternatives_considered: list[str] = Field(default_factory=list)
59
+ pros: list[Claim] = Field(default_factory=list)
60
+ cons: list[Claim] = Field(default_factory=list)
61
+
62
+
63
+ class DesignDocSection(BaseModel):
64
+ heading: str # "Technology choices"
65
+ claims: list[Claim] = Field(default_factory=list)
66
+ related_node_ids: list[str] = Field(default_factory=list) # cross-links into the archify IR
67
+ tradeoffs: list[Tradeoff] = Field(default_factory=list)
68
+
69
+
70
+ class QuestionOption(BaseModel):
71
+ label: str # short label, e.g. "Type-hints + Rich dashboards"
72
+ becomes_text: str # exact confirmed claim text if this option is chosen
73
+
74
+
75
+ class RationaleQuestion(BaseModel):
76
+ """One askable gap, per plan.md §03.
77
+
78
+ Only descriptive claims with zero evidence from the mining rubric AND
79
+ load-bearing enough to matter (landed in Technology Choices or Tradeoffs)
80
+ become a RationaleQuestion. Renders identically whether the surface is an
81
+ agent host's structured-question tool or a bare terminal prompt - see
82
+ graphitect.synthesize.questions.
83
+ """
84
+
85
+ claim_id: str
86
+ question: str
87
+ options: list[QuestionOption] # options[0] is always Synthesize's own best guess
88
+ allow_free_text: bool = True
89
+
90
+
91
+ class GroundedUnderstanding(BaseModel):
92
+ diagram_kind: Literal["architecture", "workflow", "sequence", "dataflow", "lifecycle"]
93
+ nodes: list[dict] = Field(default_factory=list) # mapped into archify's own node schema
94
+ edges: list[dict] = Field(default_factory=list)
95
+ doc: list[DesignDocSection] = Field(default_factory=list)
96
+ pending_questions: list[RationaleQuestion] = Field(default_factory=list)
97
+ # Plain-language Graphify community names (community id -> label), when
98
+ # grounding came from a real graphify run that produced them. Used to
99
+ # name aggregated diagram boxes when there are too many raw nodes for a
100
+ # readable diagram - see archify_adapter._aggregate_by_community. Naman's
101
+ # point (12 Sep 2026): a large codebase's full graph either won't render
102
+ # or renders unreadably, so the diagram falls back to Graphify's own
103
+ # community-detection output instead of an LLM re-inventing a summary.
104
+ community_labels: dict[str, str] = Field(default_factory=dict)
105
+
106
+
107
+ class AgentNarrative(BaseModel):
108
+ """The only portion an installed agent may author.
109
+
110
+ Graphitect joins this with deterministic Graphify structure during
111
+ ``graphitect agent compile``. The schema deliberately excludes nodes and
112
+ edges, so a host model cannot alter the diagram it explains.
113
+ """
114
+
115
+ model_config = ConfigDict(extra="forbid")
116
+
117
+ schema_version: Literal[1] = 1
118
+ doc: list[DesignDocSection] = Field(default_factory=list)
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: graphitect
3
+ description: Generate an evidence-grounded, self-contained interactive architecture report for an existing repository. Use for codebase diagrams, architecture walkthroughs, technical-choice or trade-off explanations, and interview-preparation artifacts; do not use for greenfield architecture proposals.
4
+ license: MIT
5
+ metadata:
6
+ version: "0.2.0"
7
+ ---
8
+
9
+ # Graphitect
10
+
11
+ Use Graphitect for a repository the user already has when they want a codebase
12
+ diagram, project walkthrough, technical-choice explanation, or
13
+ interview-preparation artifact.
14
+
15
+ Do not use it to invent an architecture for a project that does not yet exist.
16
+
17
+ ## Installed-agent mode — no separate API key
18
+
19
+ When this skill runs inside Codex, Claude Code, or another agent host, use the
20
+ host's selected model for Section 2. Graphitect makes no LLM network call in
21
+ this mode.
22
+
23
+ ```bash
24
+ graphitect agent prepare <path> -o .graphitect-agent
25
+ ```
26
+
27
+ Read `.graphitect-agent/agent-context.md`,
28
+ `.graphitect-agent/narrative.schema.json`, and any source files needed to
29
+ check a claim. Edit only `.graphitect-agent/narrative.json` with detailed
30
+ `doc` sections for the project explanation, technical choices, mechanisms,
31
+ and trade-offs.
32
+
33
+ - Graphitect owns the diagram: never add, remove, or rename nodes or edges.
34
+ - Mark a claim `confirmed` only with real evidence. A code citation needs a
35
+ repository-relative `file` and a `note` that is a full phrase from that file.
36
+ - Do not use `user` evidence in `narrative.json`; only `--answers` may add a
37
+ direct user answer to the final report.
38
+ - Mark interpretation, unstated rationale, and recommendations as `inferred`.
39
+ - Use only real `related_node_ids` from the prepared grounding.
40
+
41
+ ```bash
42
+ graphitect agent compile .graphitect-agent --title <project> -o <project>-graphitect.html
43
+ ```
44
+
45
+ This validates host-written citations and writes the single self-contained
46
+ HTML artifact. If `.graphitect-agent/graphitect-questions.json` contains
47
+ unanswered entries, ask the user, fill each `answer`, then rerun `agent
48
+ compile --answers` with that same file. The first compile is still useful:
49
+ unresolved claims remain honestly labeled as inferred.
50
+
51
+ Only use `--no-diagram` when the user explicitly opts out. A diagram-rendering
52
+ failure is a command failure because Section 1 is mandatory by default.
53
+
54
+ ## Standalone CLI mode
55
+
56
+ ```bash
57
+ graphitect build <path> -o <project>-graphitect.html
58
+ ```
59
+
60
+ This single command runs the bundled Graphify analyzer, renders with the
61
+ bundled Archify viewer, and writes one HTML file. Do not install or invoke
62
+ Graphify or Archify separately.
63
+
64
+ Outside an agent host, an API key is optional. With `ANTHROPIC_API_KEY`,
65
+ `GEMINI_API_KEY`, `GOOGLE_API_KEY`, or `OLLAMA_API_KEY`, Section 2 includes
66
+ the detailed project explanation. Without a key, Section 1 still renders and
67
+ Section 2 honestly states that the narrative was skipped.
68
+
69
+ ## Verify
70
+
71
+ Confirm that the output contains both named sections and that the embedded
72
+ Archify viewer opens, pans/zooms, switches theme, exposes per-block hover
73
+ details, and exposes its route and guided-view controls.
74
+
75
+ Keep claims labeled as confirmed or inferred; never invent a citation,
76
+ technology rationale, runtime trace, or provider relationship. A workflow
77
+ arrow is a direct static Graphify relationship. A sequence appears only when
78
+ Graphify observed consecutive `calls` or `invokes` edges; it is not runtime
79
+ telemetry. Preserve the source symbol in hover details when a legacy function
80
+ name could be mistaken for provider topology.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Graphitect"
3
+ short_description: "Generate a grounded interactive codebase architecture report"
4
+ default_prompt: "Use Graphitect's host-model workflow to create an evidence-grounded, self-contained architecture report for this repository without a separate API key."
@@ -0,0 +1,5 @@
1
+ """The rationale-mining rubric and its Q&A follow-up - plan.md §03."""
2
+
3
+ from . import engine, llm_backend, questions, rubric
4
+
5
+ __all__ = ["engine", "llm_backend", "questions", "rubric"]