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.
- graphify/__init__.py +30 -0
- graphify/__main__.py +757 -0
- graphify/_minhash.py +107 -0
- graphify/affected.py +318 -0
- graphify/always_on/agents-md.md +12 -0
- graphify/always_on/antigravity-rules.md +14 -0
- graphify/always_on/claude-md.md +9 -0
- graphify/always_on/gemini-md.md +9 -0
- graphify/always_on/kiro-steering.md +5 -0
- graphify/always_on/vscode-instructions.md +17 -0
- graphify/analyze.py +769 -0
- graphify/benchmark.py +152 -0
- graphify/build.py +2300 -0
- graphify/cache.py +1746 -0
- graphify/callflow_html.py +2051 -0
- graphify/cargo_introspect.py +109 -0
- graphify/cli.py +4745 -0
- graphify/cluster.py +409 -0
- graphify/command-kilo.md +15 -0
- graphify/cross_repo_calls.py +216 -0
- graphify/cross_repo_types.py +75 -0
- graphify/csharp_dispatch.py +154 -0
- graphify/dedup.py +1213 -0
- graphify/detect.py +2566 -0
- graphify/diagnostics.py +406 -0
- graphify/export.py +1349 -0
- graphify/exporters/__init__.py +1 -0
- graphify/exporters/base.py +14 -0
- graphify/exporters/graphdb.py +173 -0
- graphify/exporters/html.py +637 -0
- graphify/extract.py +7856 -0
- graphify/extractors/MIGRATION.md +107 -0
- graphify/extractors/__init__.py +66 -0
- graphify/extractors/apex.py +215 -0
- graphify/extractors/base.py +85 -0
- graphify/extractors/bash.py +579 -0
- graphify/extractors/blade.py +53 -0
- graphify/extractors/commonlisp.py +540 -0
- graphify/extractors/csharp.py +448 -0
- graphify/extractors/dart.py +564 -0
- graphify/extractors/dm.py +494 -0
- graphify/extractors/elixir.py +241 -0
- graphify/extractors/engine.py +6509 -0
- graphify/extractors/fortran.py +311 -0
- graphify/extractors/go.py +527 -0
- graphify/extractors/json_config.py +240 -0
- graphify/extractors/julia.py +289 -0
- graphify/extractors/markdown.py +408 -0
- graphify/extractors/models.py +131 -0
- graphify/extractors/objc.py +566 -0
- graphify/extractors/ocaml.py +289 -0
- graphify/extractors/pascal.py +688 -0
- graphify/extractors/pascal_forms.py +196 -0
- graphify/extractors/powershell.py +522 -0
- graphify/extractors/razor.py +192 -0
- graphify/extractors/resolution.py +3584 -0
- graphify/extractors/robot.py +296 -0
- graphify/extractors/rust.py +470 -0
- graphify/extractors/sln.py +92 -0
- graphify/extractors/sql.py +720 -0
- graphify/extractors/terraform.py +181 -0
- graphify/extractors/verilog.py +329 -0
- graphify/extractors/zig.py +181 -0
- graphify/file_slice.py +246 -0
- graphify/global_graph.py +194 -0
- graphify/google_workspace.py +237 -0
- graphify/hooks.py +933 -0
- graphify/ids.py +93 -0
- graphify/ingest.py +358 -0
- graphify/install.py +2366 -0
- graphify/llm.py +3544 -0
- graphify/manifest.py +4 -0
- graphify/manifest_ingest.py +311 -0
- graphify/mcp_ingest.py +386 -0
- graphify/multigraph_compat.py +212 -0
- graphify/pascal_resolution.py +129 -0
- graphify/paths.py +436 -0
- graphify/pg_introspect.py +165 -0
- graphify/prs.py +770 -0
- graphify/querylog.py +80 -0
- graphify/reflect.py +882 -0
- graphify/report.py +346 -0
- graphify/resolver_registry.py +85 -0
- graphify/ruby_resolution.py +242 -0
- graphify/scip_ingest.py +363 -0
- graphify/security.py +460 -0
- graphify/semantic_cleanup.py +336 -0
- graphify/serve.py +2608 -0
- graphify/skill-agents.md +710 -0
- graphify/skill-aider.md +1283 -0
- graphify/skill-amp.md +710 -0
- graphify/skill-claw.md +713 -0
- graphify/skill-codex.md +710 -0
- graphify/skill-copilot.md +713 -0
- graphify/skill-devin.md +1410 -0
- graphify/skill-droid.md +710 -0
- graphify/skill-kilo.md +722 -0
- graphify/skill-kiro.md +713 -0
- graphify/skill-opencode.md +705 -0
- graphify/skill-pi.md +713 -0
- graphify/skill-trae.md +711 -0
- graphify/skill-vscode.md +709 -0
- graphify/skill-windows.md +755 -0
- graphify/skill.md +713 -0
- graphify/skills/agents/references/add-watch.md +56 -0
- graphify/skills/agents/references/exports.md +87 -0
- graphify/skills/agents/references/extraction-spec.md +70 -0
- graphify/skills/agents/references/github-and-merge.md +46 -0
- graphify/skills/agents/references/hooks.md +33 -0
- graphify/skills/agents/references/query.md +311 -0
- graphify/skills/agents/references/transcribe.md +52 -0
- graphify/skills/agents/references/update.md +210 -0
- graphify/skills/amp/references/add-watch.md +56 -0
- graphify/skills/amp/references/exports.md +87 -0
- graphify/skills/amp/references/extraction-spec.md +70 -0
- graphify/skills/amp/references/github-and-merge.md +46 -0
- graphify/skills/amp/references/hooks.md +33 -0
- graphify/skills/amp/references/query.md +311 -0
- graphify/skills/amp/references/transcribe.md +52 -0
- graphify/skills/amp/references/update.md +210 -0
- graphify/skills/claude/references/add-watch.md +56 -0
- graphify/skills/claude/references/exports.md +87 -0
- graphify/skills/claude/references/extraction-spec.md +70 -0
- graphify/skills/claude/references/github-and-merge.md +46 -0
- graphify/skills/claude/references/hooks.md +33 -0
- graphify/skills/claude/references/query.md +311 -0
- graphify/skills/claude/references/transcribe.md +52 -0
- graphify/skills/claude/references/update.md +210 -0
- graphify/skills/claw/references/add-watch.md +56 -0
- graphify/skills/claw/references/exports.md +87 -0
- graphify/skills/claw/references/extraction-spec.md +31 -0
- graphify/skills/claw/references/github-and-merge.md +46 -0
- graphify/skills/claw/references/hooks.md +33 -0
- graphify/skills/claw/references/query.md +311 -0
- graphify/skills/claw/references/transcribe.md +52 -0
- graphify/skills/claw/references/update.md +210 -0
- graphify/skills/codex/references/add-watch.md +56 -0
- graphify/skills/codex/references/exports.md +87 -0
- graphify/skills/codex/references/extraction-spec.md +31 -0
- graphify/skills/codex/references/github-and-merge.md +46 -0
- graphify/skills/codex/references/hooks.md +33 -0
- graphify/skills/codex/references/query.md +311 -0
- graphify/skills/codex/references/transcribe.md +52 -0
- graphify/skills/codex/references/update.md +210 -0
- graphify/skills/copilot/references/add-watch.md +56 -0
- graphify/skills/copilot/references/exports.md +87 -0
- graphify/skills/copilot/references/extraction-spec.md +70 -0
- graphify/skills/copilot/references/github-and-merge.md +46 -0
- graphify/skills/copilot/references/hooks.md +33 -0
- graphify/skills/copilot/references/query.md +311 -0
- graphify/skills/copilot/references/transcribe.md +52 -0
- graphify/skills/copilot/references/update.md +210 -0
- graphify/skills/droid/references/add-watch.md +56 -0
- graphify/skills/droid/references/exports.md +87 -0
- graphify/skills/droid/references/extraction-spec.md +70 -0
- graphify/skills/droid/references/github-and-merge.md +46 -0
- graphify/skills/droid/references/hooks.md +33 -0
- graphify/skills/droid/references/query.md +311 -0
- graphify/skills/droid/references/transcribe.md +52 -0
- graphify/skills/droid/references/update.md +210 -0
- graphify/skills/kilo/references/add-watch.md +56 -0
- graphify/skills/kilo/references/exports.md +87 -0
- graphify/skills/kilo/references/extraction-spec.md +70 -0
- graphify/skills/kilo/references/github-and-merge.md +46 -0
- graphify/skills/kilo/references/hooks.md +33 -0
- graphify/skills/kilo/references/query.md +311 -0
- graphify/skills/kilo/references/transcribe.md +52 -0
- graphify/skills/kilo/references/update.md +210 -0
- graphify/skills/kiro/references/add-watch.md +56 -0
- graphify/skills/kiro/references/exports.md +87 -0
- graphify/skills/kiro/references/extraction-spec.md +31 -0
- graphify/skills/kiro/references/github-and-merge.md +46 -0
- graphify/skills/kiro/references/hooks.md +33 -0
- graphify/skills/kiro/references/query.md +311 -0
- graphify/skills/kiro/references/transcribe.md +52 -0
- graphify/skills/kiro/references/update.md +210 -0
- graphify/skills/opencode/references/add-watch.md +56 -0
- graphify/skills/opencode/references/exports.md +87 -0
- graphify/skills/opencode/references/extraction-spec.md +70 -0
- graphify/skills/opencode/references/github-and-merge.md +46 -0
- graphify/skills/opencode/references/hooks.md +33 -0
- graphify/skills/opencode/references/query.md +311 -0
- graphify/skills/opencode/references/transcribe.md +52 -0
- graphify/skills/opencode/references/update.md +210 -0
- graphify/skills/pi/references/add-watch.md +56 -0
- graphify/skills/pi/references/exports.md +87 -0
- graphify/skills/pi/references/extraction-spec.md +31 -0
- graphify/skills/pi/references/github-and-merge.md +46 -0
- graphify/skills/pi/references/hooks.md +33 -0
- graphify/skills/pi/references/query.md +311 -0
- graphify/skills/pi/references/transcribe.md +52 -0
- graphify/skills/pi/references/update.md +210 -0
- graphify/skills/trae/references/add-watch.md +56 -0
- graphify/skills/trae/references/exports.md +87 -0
- graphify/skills/trae/references/extraction-spec.md +70 -0
- graphify/skills/trae/references/github-and-merge.md +46 -0
- graphify/skills/trae/references/hooks.md +35 -0
- graphify/skills/trae/references/query.md +311 -0
- graphify/skills/trae/references/transcribe.md +52 -0
- graphify/skills/trae/references/update.md +210 -0
- graphify/skills/vscode/references/add-watch.md +56 -0
- graphify/skills/vscode/references/exports.md +87 -0
- graphify/skills/vscode/references/extraction-spec.md +70 -0
- graphify/skills/vscode/references/github-and-merge.md +46 -0
- graphify/skills/vscode/references/hooks.md +33 -0
- graphify/skills/vscode/references/query.md +311 -0
- graphify/skills/vscode/references/transcribe.md +52 -0
- graphify/skills/vscode/references/update.md +210 -0
- graphify/skills/windows/references/add-watch.md +56 -0
- graphify/skills/windows/references/exports.md +87 -0
- graphify/skills/windows/references/extraction-spec.md +70 -0
- graphify/skills/windows/references/github-and-merge.md +46 -0
- graphify/skills/windows/references/hooks.md +33 -0
- graphify/skills/windows/references/query.md +311 -0
- graphify/skills/windows/references/transcribe.md +52 -0
- graphify/skills/windows/references/update.md +210 -0
- graphify/symbol_resolution.py +556 -0
- graphify/transcribe.py +186 -0
- graphify/tree_html.py +603 -0
- graphify/validate.py +95 -0
- graphify/watch.py +2280 -0
- graphify/wiki.py +405 -0
- graphitect/__init__.py +28 -0
- graphitect/__main__.py +4 -0
- graphitect/_vendor/__init__.py +2 -0
- graphitect/_vendor/archify/LICENSE +22 -0
- graphitect/_vendor/archify/SKILL.md +137 -0
- graphitect/_vendor/archify/THIRD_PARTY_NOTICES.md +69 -0
- graphitect/_vendor/archify/assets/JetBrainsMono-OFL.txt +93 -0
- graphitect/_vendor/archify/assets/template.html +14935 -0
- graphitect/_vendor/archify/bin/archify.mjs +2091 -0
- graphitect/_vendor/archify/bin/open-artifact.mjs +86 -0
- graphitect/_vendor/archify/bin/preview.mjs +653 -0
- graphitect/_vendor/archify/bin/visual-check.mjs +829 -0
- graphitect/_vendor/archify/brand-marks/README.md +31 -0
- graphitect/_vendor/archify/brand-marks/catalog.json +131 -0
- graphitect/_vendor/archify/delta/architecture-delta.mjs +1221 -0
- graphitect/_vendor/archify/examples/agent-run.lifecycle.json +60 -0
- graphitect/_vendor/archify/examples/agent-tool-call.workflow.json +94 -0
- graphitect/_vendor/archify/examples/async-job-roundtrip.sequence.json +61 -0
- graphitect/_vendor/archify/examples/brand-aware-delivery.architecture.json +47 -0
- graphitect/_vendor/archify/examples/cache-miss-request.sequence.json +82 -0
- graphitect/_vendor/archify/examples/checkout-platform.base.architecture.json +31 -0
- graphitect/_vendor/archify/examples/checkout-platform.head.architecture.json +31 -0
- graphitect/_vendor/archify/examples/dataflow-product-analytics.html +15045 -0
- graphitect/_vendor/archify/examples/deployment-release.lifecycle.json +49 -0
- graphitect/_vendor/archify/examples/event-stream.dataflow.json +57 -0
- graphitect/_vendor/archify/examples/incident-response.workflow.json +64 -0
- graphitect/_vendor/archify/examples/lifecycle-agent-run.html +14980 -0
- graphitect/_vendor/archify/examples/product-analytics.dataflow.json +76 -0
- graphitect/_vendor/archify/examples/production-deployment.architecture.json +71 -0
- graphitect/_vendor/archify/examples/release-delivery.workflow.json +62 -0
- graphitect/_vendor/archify/examples/sequence-cache-miss-request.html +15060 -0
- graphitect/_vendor/archify/examples/web-app-rendered.html +15009 -0
- graphitect/_vendor/archify/examples/web-app.architecture.json +46 -0
- graphitect/_vendor/archify/examples/workflow-agent-tool-call-rendered.html +15051 -0
- graphitect/_vendor/archify/migrations/workflow-v2.mjs +279 -0
- graphitect/_vendor/archify/package-lock.json +149 -0
- graphitect/_vendor/archify/package.json +39 -0
- graphitect/_vendor/archify/recipes/scenarios.mjs +391 -0
- graphitect/_vendor/archify/references/authoring-contract.md +243 -0
- graphitect/_vendor/archify/references/brand-marks.md +65 -0
- graphitect/_vendor/archify/references/delivery-contract.md +120 -0
- graphitect/_vendor/archify/references/viewer-runtime.md +45 -0
- graphitect/_vendor/archify/renderers/architecture/grid.mjs +62 -0
- graphitect/_vendor/archify/renderers/architecture/render-architecture.mjs +1078 -0
- graphitect/_vendor/archify/renderers/dataflow/README.md +104 -0
- graphitect/_vendor/archify/renderers/dataflow/render-dataflow.mjs +483 -0
- graphitect/_vendor/archify/renderers/lifecycle/README.md +115 -0
- graphitect/_vendor/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
- graphitect/_vendor/archify/renderers/sequence/README.md +114 -0
- graphitect/_vendor/archify/renderers/sequence/render-sequence.mjs +464 -0
- graphitect/_vendor/archify/renderers/shared/brand-marks.mjs +563 -0
- graphitect/_vendor/archify/renderers/shared/cli.mjs +218 -0
- graphitect/_vendor/archify/renderers/shared/desktop-readability.mjs +26 -0
- graphitect/_vendor/archify/renderers/shared/diagnostics.mjs +127 -0
- graphitect/_vendor/archify/renderers/shared/engineering-profiles.mjs +157 -0
- graphitect/_vendor/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
- graphitect/_vendor/archify/renderers/shared/generated-validators.mjs +13 -0
- graphitect/_vendor/archify/renderers/shared/geometry.mjs +1423 -0
- graphitect/_vendor/archify/renderers/shared/i18n.mjs +595 -0
- graphitect/_vendor/archify/renderers/shared/layout-report.mjs +40 -0
- graphitect/_vendor/archify/renderers/shared/legend.mjs +217 -0
- graphitect/_vendor/archify/renderers/shared/output-path.mjs +340 -0
- graphitect/_vendor/archify/renderers/shared/repository-evidence.mjs +238 -0
- graphitect/_vendor/archify/renderers/shared/repository-location.mjs +58 -0
- graphitect/_vendor/archify/renderers/shared/text-fit.mjs +49 -0
- graphitect/_vendor/archify/renderers/shared/utils.mjs +232 -0
- graphitect/_vendor/archify/renderers/shared/validator.mjs +86 -0
- graphitect/_vendor/archify/renderers/workflow/README.md +223 -0
- graphitect/_vendor/archify/renderers/workflow/render-workflow.mjs +35 -0
- graphitect/_vendor/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
- graphitect/_vendor/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
- graphitect/_vendor/archify/schemas/README.md +211 -0
- graphitect/_vendor/archify/schemas/architecture.schema.json +178 -0
- graphitect/_vendor/archify/schemas/common.schema.json +115 -0
- graphitect/_vendor/archify/schemas/dataflow.schema.json +243 -0
- graphitect/_vendor/archify/schemas/lifecycle.schema.json +266 -0
- graphitect/_vendor/archify/schemas/sequence.schema.json +223 -0
- graphitect/_vendor/archify/schemas/workflow.schema.json +428 -0
- graphitect/_vendor/archify/scripts/check-render-output.mjs +836 -0
- graphitect/_vendor/archify/scripts/check-update.mjs +1667 -0
- graphitect/_vendor/archify/scripts/generate-brand-marks.mjs +141 -0
- graphitect/_vendor/archify/scripts/generate-validators.mjs +66 -0
- graphitect/_vendor/archify/scripts/render-examples.mjs +26 -0
- graphitect/_vendor/archify/scripts/update-contract.mjs +182 -0
- graphitect/_vendor/archify/skill-release.json +10 -0
- graphitect/cli.py +981 -0
- graphitect/deliver/__init__.py +5 -0
- graphitect/deliver/archify_adapter.py +1877 -0
- graphitect/deliver/archify_ir.py +160 -0
- graphitect/deliver/archify_repair.py +135 -0
- graphitect/deliver/doc_compiler.py +916 -0
- graphitect/ground/__init__.py +5 -0
- graphitect/ground/describe_source.py +27 -0
- graphitect/ground/fullread_source.py +56 -0
- graphitect/ground/graphify_source.py +107 -0
- graphitect/models.py +118 -0
- graphitect/skill/SKILL.md +80 -0
- graphitect/skill/agents/openai.yaml +4 -0
- graphitect/synthesize/__init__.py +5 -0
- graphitect/synthesize/engine.py +281 -0
- graphitect/synthesize/llm_backend.py +331 -0
- graphitect/synthesize/questions.py +139 -0
- graphitect/synthesize/rubric.py +104 -0
- graphitect-0.2.0.dist-info/METADATA +284 -0
- graphitect-0.2.0.dist-info/RECORD +336 -0
- graphitect-0.2.0.dist-info/WHEEL +5 -0
- graphitect-0.2.0.dist-info/entry_points.txt +2 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE +21 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-ARCHIFY-MIT +22 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-APACHE-2.0 +202 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-MIT +21 -0
- graphitect-0.2.0.dist-info/licenses/NOTICE-ARCHIFY-THIRD-PARTY.md +69 -0
- graphitect-0.2.0.dist-info/licenses/NOTICE-GRAPHIFY +8 -0
- graphitect-0.2.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Two renderers, one RationaleQuestion object - plan.md §03.
|
|
2
|
+
|
|
3
|
+
The skill surface maps a RationaleQuestion straight onto the host's
|
|
4
|
+
structured-question tool (e.g. Claude Code's AskUserQuestion) - that mapping
|
|
5
|
+
lives in the SKILL.md itself, not here, since it's a host-tool-call, not
|
|
6
|
+
Python. This module is the standalone-CLI renderer: a numbered terminal
|
|
7
|
+
prompt when interactive, or a JSON file round-trip when not - matching
|
|
8
|
+
Graphify's own `--update` re-run convention rather than inventing a new one.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from ..models import Claim, Confidence, Evidence, RationaleQuestion
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def ask_interactive(questions: list[RationaleQuestion]) -> dict[str, str]:
|
|
21
|
+
"""Numbered terminal prompt with a free-text escape hatch. Returns
|
|
22
|
+
{claim_id: answer_text} - either the chosen option's becomes_text or the
|
|
23
|
+
typed free text, verbatim.
|
|
24
|
+
"""
|
|
25
|
+
answers: dict[str, str] = {}
|
|
26
|
+
total = len(questions)
|
|
27
|
+
for i, q in enumerate(questions, start=1):
|
|
28
|
+
print(f"\n[{i}/{total}] {q.question}")
|
|
29
|
+
for j, opt in enumerate(q.options, start=1):
|
|
30
|
+
marker = " [our best guess]" if j == 1 else ""
|
|
31
|
+
print(f" {j}) {opt.label}{marker}")
|
|
32
|
+
if q.allow_free_text:
|
|
33
|
+
print(f" {len(q.options) + 1}) Something else (type your own)")
|
|
34
|
+
try:
|
|
35
|
+
choice = input("> ").strip()
|
|
36
|
+
except EOFError:
|
|
37
|
+
# No real terminal behind stdin despite isatty() saying so (seen
|
|
38
|
+
# under some sandboxed/wrapped shells) - stop asking rather than
|
|
39
|
+
# crash; caller falls back to writing out whatever's left unanswered.
|
|
40
|
+
print("\n(no input available - leaving remaining questions unanswered)")
|
|
41
|
+
break
|
|
42
|
+
|
|
43
|
+
if choice.isdigit() and 1 <= int(choice) <= len(q.options):
|
|
44
|
+
answers[q.claim_id] = q.options[int(choice) - 1].becomes_text
|
|
45
|
+
elif q.allow_free_text:
|
|
46
|
+
free_text = choice if not choice.isdigit() else input("Your answer: ").strip()
|
|
47
|
+
answers[q.claim_id] = free_text
|
|
48
|
+
else:
|
|
49
|
+
print("No valid option chosen - leaving this claim inferred.")
|
|
50
|
+
return answers
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def write_pending(questions: list[RationaleQuestion], out_path: Path) -> Path:
|
|
54
|
+
"""Non-interactive path: don't block CI/piped runs. Write pending
|
|
55
|
+
questions to disk for a human to answer later via `graphitect synthesize
|
|
56
|
+
--answers <file>`. Set each emitted `answer` field to a string, then pass
|
|
57
|
+
the same file back to `--answers`.
|
|
58
|
+
"""
|
|
59
|
+
payload = [{**q.model_dump(), "answer": None} for q in questions]
|
|
60
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
out_path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
|
62
|
+
return out_path
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def read_answers(answers_path: Path) -> dict[str, str]:
|
|
66
|
+
"""Load answers written by a human editing the file written by
|
|
67
|
+
write_pending. The preferred format is its question list with an `answer`
|
|
68
|
+
string filled per item. The older {"claim_id": "answer text"} mapping is
|
|
69
|
+
accepted for compatibility.
|
|
70
|
+
"""
|
|
71
|
+
payload = json.loads(answers_path.read_text(encoding="utf-8"))
|
|
72
|
+
if isinstance(payload, dict):
|
|
73
|
+
if not all(isinstance(claim_id, str) and isinstance(answer, str) for claim_id, answer in payload.items()):
|
|
74
|
+
raise TypeError("answer mappings must contain string claim IDs and answer text")
|
|
75
|
+
return payload
|
|
76
|
+
if not isinstance(payload, list):
|
|
77
|
+
raise TypeError("answers must be an object or the generated question list")
|
|
78
|
+
|
|
79
|
+
answers: dict[str, str] = {}
|
|
80
|
+
for index, item in enumerate(payload, start=1):
|
|
81
|
+
if not isinstance(item, dict) or not isinstance(item.get("claim_id"), str):
|
|
82
|
+
raise TypeError(f"question {index} must contain a string claim_id")
|
|
83
|
+
answer = item.get("answer")
|
|
84
|
+
if answer is None or answer == "":
|
|
85
|
+
continue
|
|
86
|
+
if not isinstance(answer, str):
|
|
87
|
+
raise TypeError(f"question {index} answer must be a string or null")
|
|
88
|
+
if item["claim_id"] in answers:
|
|
89
|
+
raise ValueError(f"duplicate answer for claim_id {item['claim_id']!r}")
|
|
90
|
+
answers[item["claim_id"]] = answer
|
|
91
|
+
return answers
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def apply_answer(claim: Claim, answer_text: str) -> Claim:
|
|
95
|
+
"""An answer always confirms - and, if it's free text rather than a
|
|
96
|
+
listed option, *rewrites* claim.text to match what was actually said.
|
|
97
|
+
That's what let a wrong guess (e.g. Phase 0's Word-COM inference) get
|
|
98
|
+
genuinely corrected instead of rubber-stamped (plan.md §03).
|
|
99
|
+
"""
|
|
100
|
+
return claim.model_copy(
|
|
101
|
+
update={
|
|
102
|
+
"text": answer_text,
|
|
103
|
+
"confidence": Confidence.CONFIRMED,
|
|
104
|
+
"cites": [*claim.cites, Evidence(source="user", note=answer_text)],
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def resolve_questions(
|
|
110
|
+
questions: list[RationaleQuestion],
|
|
111
|
+
claims_by_id: dict[str, Claim],
|
|
112
|
+
pending_path: Path,
|
|
113
|
+
*,
|
|
114
|
+
non_interactive: bool = False,
|
|
115
|
+
) -> tuple[dict[str, Claim], list[RationaleQuestion]]:
|
|
116
|
+
"""Interactive when attached to a real terminal, otherwise write pending
|
|
117
|
+
questions to disk and leave those claims inferred for this run.
|
|
118
|
+
|
|
119
|
+
`non_interactive` is an explicit override for `--non-interactive`/CI use -
|
|
120
|
+
isatty() alone isn't reliable everywhere (some wrapped/sandboxed shells
|
|
121
|
+
report a tty even with stdin redirected from /dev/null), and a dropped
|
|
122
|
+
stdin mid-prompt raises EOFError rather than silently hanging, so this
|
|
123
|
+
always degrades to write_pending for whatever wasn't answered rather than
|
|
124
|
+
crashing.
|
|
125
|
+
"""
|
|
126
|
+
if not questions:
|
|
127
|
+
return claims_by_id, []
|
|
128
|
+
|
|
129
|
+
if non_interactive or not sys.stdin.isatty():
|
|
130
|
+
write_pending(questions, pending_path)
|
|
131
|
+
return claims_by_id, questions
|
|
132
|
+
|
|
133
|
+
answers = ask_interactive(questions)
|
|
134
|
+
for claim_id, answer_text in answers.items():
|
|
135
|
+
claims_by_id[claim_id] = apply_answer(claims_by_id[claim_id], answer_text)
|
|
136
|
+
unanswered = [q for q in questions if q.claim_id not in answers]
|
|
137
|
+
if unanswered:
|
|
138
|
+
write_pending(unanswered, pending_path)
|
|
139
|
+
return claims_by_id, unanswered
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""The rationale-mining rubric - plan.md §03.
|
|
2
|
+
|
|
3
|
+
For each claim: code -> README -> git log -> other docs -> stop. If nothing
|
|
4
|
+
found, only *descriptive* claims in a load-bearing section become an askable
|
|
5
|
+
RationaleQuestion; *prescriptive* claims (recommendations, "not a stated
|
|
6
|
+
plan") stay `inferred` forever by construction - asking "did you really mean
|
|
7
|
+
this suggestion" doesn't make sense the same way a factual gap does.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import subprocess
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from ..models import Claim, Confidence, Evidence, QuestionOption, RationaleQuestion
|
|
16
|
+
|
|
17
|
+
# Only these sections are worth a targeted question - incidental color in
|
|
18
|
+
# Overview/Components/Workflows isn't "why" material (plan.md §03).
|
|
19
|
+
ASKABLE_SECTIONS = {"Technology choices & why", "Tradeoffs & alternatives considered"}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def search_text(text: str, keywords: list[str]) -> str | None:
|
|
23
|
+
"""Return the first line containing any keyword, or None. A real
|
|
24
|
+
implementation would use embeddings/fuzzy match; keyword search is the
|
|
25
|
+
honest floor - it either finds explicit textual evidence or it doesn't,
|
|
26
|
+
with no risk of a false-confident semantic match standing in for a
|
|
27
|
+
citation.
|
|
28
|
+
"""
|
|
29
|
+
lowered_keywords = [k.lower() for k in keywords]
|
|
30
|
+
for line in text.splitlines():
|
|
31
|
+
low = line.lower()
|
|
32
|
+
if any(k in low for k in lowered_keywords):
|
|
33
|
+
return line.strip()
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def mine_readme(repo_path: Path, keywords: list[str]) -> Evidence | None:
|
|
38
|
+
readme = repo_path / "README.md"
|
|
39
|
+
if not readme.exists():
|
|
40
|
+
return None
|
|
41
|
+
hit = search_text(readme.read_text(encoding="utf-8", errors="ignore"), keywords)
|
|
42
|
+
return Evidence(source="readme", file="README.md", note=hit) if hit else None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def mine_git_log(repo_path: Path, keywords: list[str]) -> Evidence | None:
|
|
46
|
+
changelog = repo_path / "CHANGELOG.md"
|
|
47
|
+
if changelog.exists():
|
|
48
|
+
hit = search_text(changelog.read_text(encoding="utf-8", errors="ignore"), keywords)
|
|
49
|
+
if hit:
|
|
50
|
+
return Evidence(source="git_log", file="CHANGELOG.md", note=hit)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
result = subprocess.run(
|
|
54
|
+
["git", "log", "--all", "--grep", "|".join(keywords), "-i", "--oneline", "-n", "1"],
|
|
55
|
+
cwd=repo_path,
|
|
56
|
+
capture_output=True,
|
|
57
|
+
text=True,
|
|
58
|
+
encoding="utf-8",
|
|
59
|
+
errors="replace",
|
|
60
|
+
check=False,
|
|
61
|
+
)
|
|
62
|
+
except FileNotFoundError:
|
|
63
|
+
return None
|
|
64
|
+
hit = result.stdout.strip()
|
|
65
|
+
return Evidence(source="git_log", note=hit) if hit else None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def mine_other_docs(repo_path: Path, keywords: list[str]) -> Evidence | None:
|
|
69
|
+
docs_dir = repo_path / "docs"
|
|
70
|
+
if not docs_dir.is_dir():
|
|
71
|
+
return None
|
|
72
|
+
for doc in sorted(docs_dir.rglob("*.md")):
|
|
73
|
+
hit = search_text(doc.read_text(encoding="utf-8", errors="ignore"), keywords)
|
|
74
|
+
if hit:
|
|
75
|
+
return Evidence(source="docs", file=str(doc.relative_to(repo_path)), note=hit)
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def mine_rationale(repo_path: Path, claim_text: str, keywords: list[str]) -> Evidence | None:
|
|
80
|
+
"""Walk the rubric in order, stop at the first hit. Code-level evidence
|
|
81
|
+
(step 1) isn't handled here - that comes pre-attached from Graphify's own
|
|
82
|
+
extraction (EXTRACTED edges) or a direct source read, not a text search.
|
|
83
|
+
"""
|
|
84
|
+
for miner in (mine_readme, mine_git_log, mine_other_docs):
|
|
85
|
+
evidence = miner(repo_path, keywords)
|
|
86
|
+
if evidence:
|
|
87
|
+
return evidence
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def build_question(claim: Claim, claim_id: str, section: str, guess: str) -> RationaleQuestion | None:
|
|
92
|
+
"""Only queue a question for a descriptive, load-bearing, unresolved claim."""
|
|
93
|
+
if claim.kind != "descriptive" or section not in ASKABLE_SECTIONS:
|
|
94
|
+
return None
|
|
95
|
+
if claim.confidence == Confidence.CONFIRMED:
|
|
96
|
+
return None
|
|
97
|
+
return RationaleQuestion(
|
|
98
|
+
claim_id=claim_id,
|
|
99
|
+
question=f"Why: {claim.text}?",
|
|
100
|
+
options=[
|
|
101
|
+
QuestionOption(label=guess, becomes_text=claim.text),
|
|
102
|
+
QuestionOption(label="No deeper reason", becomes_text=f"{claim.text} (no deliberate reason given)"),
|
|
103
|
+
],
|
|
104
|
+
)
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: graphitect
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: One self-contained codebase explainer: bundled Graphify analysis, bundled Archify diagrams, and optional LLM rationale.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/Naman6019/graphitect
|
|
7
|
+
Project-URL: Repository, https://github.com/Naman6019/graphitect
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: LICENSE-GRAPHIFY-APACHE-2.0
|
|
12
|
+
License-File: LICENSE-GRAPHIFY-MIT
|
|
13
|
+
License-File: NOTICE-GRAPHIFY
|
|
14
|
+
License-File: LICENSE-ARCHIFY-MIT
|
|
15
|
+
License-File: NOTICE-ARCHIFY-THIRD-PARTY.md
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: networkx>=3.4
|
|
18
|
+
Requires-Dist: numpy>=1.21
|
|
19
|
+
Requires-Dist: rapidfuzz>=3.0
|
|
20
|
+
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
|
|
21
|
+
Requires-Dist: tree-sitter<0.26,>=0.23.0
|
|
22
|
+
Requires-Dist: tree-sitter-python<0.26,>=0.23
|
|
23
|
+
Requires-Dist: tree-sitter-javascript<0.26,>=0.23
|
|
24
|
+
Requires-Dist: tree-sitter-typescript<0.25,>=0.23
|
|
25
|
+
Requires-Dist: tree-sitter-go<0.26,>=0.23
|
|
26
|
+
Requires-Dist: tree-sitter-rust<0.25,>=0.23
|
|
27
|
+
Requires-Dist: tree-sitter-java<0.25,>=0.23
|
|
28
|
+
Requires-Dist: tree-sitter-groovy<0.3,>=0.1
|
|
29
|
+
Requires-Dist: tree-sitter-c<0.25,>=0.23
|
|
30
|
+
Requires-Dist: tree-sitter-cpp<0.25,>=0.23
|
|
31
|
+
Requires-Dist: tree-sitter-ruby<0.25,>=0.23
|
|
32
|
+
Requires-Dist: tree-sitter-c-sharp<0.25,>=0.23
|
|
33
|
+
Requires-Dist: tree-sitter-kotlin<2.0,>=1.0
|
|
34
|
+
Requires-Dist: tree-sitter-scala<0.27,>=0.23
|
|
35
|
+
Requires-Dist: tree-sitter-php<0.25,>=0.23
|
|
36
|
+
Requires-Dist: tree-sitter-swift<0.9,>=0.7
|
|
37
|
+
Requires-Dist: tree-sitter-lua<0.6,>=0.2
|
|
38
|
+
Requires-Dist: tree-sitter-zig<2.0,>=1.0
|
|
39
|
+
Requires-Dist: tree-sitter-powershell<0.28,>=0.26
|
|
40
|
+
Requires-Dist: tree-sitter-elixir<0.5,>=0.3
|
|
41
|
+
Requires-Dist: tree-sitter-objc<4.0,>=3.0
|
|
42
|
+
Requires-Dist: tree-sitter-julia<0.25,>=0.23
|
|
43
|
+
Requires-Dist: tree-sitter-verilog<2.0,>=1.0
|
|
44
|
+
Requires-Dist: tree-sitter-fortran<0.8,>=0.6
|
|
45
|
+
Requires-Dist: tree-sitter-bash<0.27,>=0.23
|
|
46
|
+
Requires-Dist: tree-sitter-json<0.26,>=0.23
|
|
47
|
+
Requires-Dist: tree-sitter-sql
|
|
48
|
+
Requires-Dist: openai
|
|
49
|
+
Requires-Dist: anthropic
|
|
50
|
+
Requires-Dist: tiktoken
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
# Graphitect
|
|
54
|
+
|
|
55
|
+
**Turn an existing codebase into one interactive architecture report.**
|
|
56
|
+
|
|
57
|
+
Graphitect produces a self-contained HTML artifact for project walkthroughs,
|
|
58
|
+
technical interviews, handoffs, and architectural review. It has two sections:
|
|
59
|
+
|
|
60
|
+
1. **Interactive system diagram** — generated locally from the repository.
|
|
61
|
+
2. **Project explanation** — technical choices, mechanisms, trade-offs, and
|
|
62
|
+
pros/cons, with every statement marked confirmed or inferred.
|
|
63
|
+
|
|
64
|
+

|
|
65
|
+
|
|
66
|
+
*A live Graphitect report with a responsive embedded Archify viewer. Theme,
|
|
67
|
+
view, presentation, and export controls remain interactive inside the report.*
|
|
68
|
+
|
|
69
|
+
## Why Graphitect
|
|
70
|
+
|
|
71
|
+
Reading a repository is slow when a graph tells you only **what** connects and
|
|
72
|
+
a prose summary tells you only **why**. Graphitect combines both without
|
|
73
|
+
letting a model invent the diagram:
|
|
74
|
+
|
|
75
|
+
| Layer | What it does |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| **Graphify** | Extracts code structure, direct relationships, and communities locally. It is the deterministic source for diagram nodes and edges. |
|
|
78
|
+
| **Archify** | Renders the bundled, interactive architecture, workflow, and sequence views. |
|
|
79
|
+
| **Graphitect** | Turns that evidence into one portable HTML report and verifies any file-backed explanation citation before publishing it. |
|
|
80
|
+
|
|
81
|
+
The diagram does not require an LLM or API key. The explanation can come from
|
|
82
|
+
a configured standalone provider or the model already running inside Codex,
|
|
83
|
+
Claude Code, or another Agent Skills-compatible host.
|
|
84
|
+
|
|
85
|
+
## Requirements
|
|
86
|
+
|
|
87
|
+
- Python 3.10+
|
|
88
|
+
- Node.js 18+ for the bundled Archify renderer
|
|
89
|
+
|
|
90
|
+
Graphify and Archify are bundled with Graphitect. You do **not** install
|
|
91
|
+
Graphify separately or run `npm install` for Archify.
|
|
92
|
+
|
|
93
|
+
## Install
|
|
94
|
+
|
|
95
|
+
### From this repository
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
git clone https://github.com/Naman6019/graphitect.git
|
|
99
|
+
cd graphitect
|
|
100
|
+
python -m pip install .
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### From PyPI
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
python -m pip install graphitect
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Confirm that the renderer runtime is available:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
node --version
|
|
113
|
+
graphitect --help
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Quick start
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
graphitect build /path/to/project -o project-architecture.html
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This produces one standalone HTML file. Open it in any modern browser; it does
|
|
123
|
+
not need a server or an internet connection after generation.
|
|
124
|
+
|
|
125
|
+
Without an LLM key, Graphitect still produces Section 1 and plainly marks
|
|
126
|
+
Section 2 as unavailable. To explicitly omit the diagram:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
graphitect build /path/to/project --no-diagram -o project-explanation.html
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Add the detailed explanation
|
|
133
|
+
|
|
134
|
+
### Standalone CLI
|
|
135
|
+
|
|
136
|
+
Configure one supported provider, then use the same command:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# PowerShell example — do not commit keys to your repository.
|
|
140
|
+
$env:GEMINI_API_KEY = "..."
|
|
141
|
+
graphitect build /path/to/project -o project-architecture.html
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Supported environment variables are `GEMINI_API_KEY` (or `GOOGLE_API_KEY`),
|
|
145
|
+
`ANTHROPIC_API_KEY`, and `OLLAMA_API_KEY`. A local Ollama server is also
|
|
146
|
+
supported through `--ollama-local`.
|
|
147
|
+
|
|
148
|
+
## Install as an agent skill — no separate API key
|
|
149
|
+
|
|
150
|
+
Install the `graphitect` CLI once, then export a **project skill** inside each
|
|
151
|
+
repository you want an agent to explain. The agent host's selected model writes
|
|
152
|
+
Section 2; Graphitect makes no LLM network call in this path.
|
|
153
|
+
|
|
154
|
+
### Codex
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# One time, if Graphitect is not installed already.
|
|
158
|
+
python -m pip install graphitect
|
|
159
|
+
|
|
160
|
+
# In the project you want to document.
|
|
161
|
+
cd /path/to/project
|
|
162
|
+
graphitect skill export --host codex
|
|
163
|
+
# Writes .agents/skills/graphitect/SKILL.md
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Open that project in Codex, then say: `Use the Graphitect skill to explain this
|
|
167
|
+
codebase and write project-architecture.html.`
|
|
168
|
+
|
|
169
|
+
### Claude Code
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# One time, if Graphitect is not installed already.
|
|
173
|
+
python -m pip install graphitect
|
|
174
|
+
|
|
175
|
+
# In the project you want to document.
|
|
176
|
+
cd /path/to/project
|
|
177
|
+
graphitect skill export --host claude-code
|
|
178
|
+
# Writes .claude/skills/graphitect/SKILL.md
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Start or reopen Claude Code in that project, then say: `Use the Graphitect
|
|
182
|
+
skill to explain this codebase and write project-architecture.html.`
|
|
183
|
+
|
|
184
|
+
### Other Agent Skills-compatible hosts
|
|
185
|
+
|
|
186
|
+
Export the portable bundle to the host's project-skill directory. Point
|
|
187
|
+
`--output` at the directory that host discovers:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
cd /path/to/project
|
|
191
|
+
graphitect skill export --output ./skills/graphitect
|
|
192
|
+
# Writes SKILL.md and agents/openai.yaml.
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### What the skill does
|
|
196
|
+
|
|
197
|
+
The agent follows this evidence-first handoff:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
graphitect agent prepare /path/to/project -o .graphitect-agent
|
|
201
|
+
# The host model writes .graphitect-agent/narrative.json from grounded evidence.
|
|
202
|
+
graphitect agent compile .graphitect-agent --title "Project name" -o project-architecture.html
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Graphitect owns the diagram in this mode. The host model can write only the
|
|
206
|
+
narrative; it cannot add, remove, or rename Graphify nodes and edges. A
|
|
207
|
+
confirmed code claim must cite a repository-relative file and a full phrase
|
|
208
|
+
from that file. Unverified, uncited, externally referenced, or fabricated
|
|
209
|
+
user-backed claims are downgraded to **inferred**.
|
|
210
|
+
|
|
211
|
+
## What the report contains
|
|
212
|
+
|
|
213
|
+
### Section 1 — Interactive system diagram
|
|
214
|
+
|
|
215
|
+
- Overview: a readable structural subset of the Graphify graph.
|
|
216
|
+
- Full architecture rollup: every retained relationship in a scrollable view.
|
|
217
|
+
- Guided workflow story: a paced, direct path through observed relationships.
|
|
218
|
+
- Sequence trace: shown only for consecutive direct `calls` or `invokes`
|
|
219
|
+
relationships; it is static source evidence, never runtime telemetry.
|
|
220
|
+
- Per-block hover details: source path, symbol, relationship context, and
|
|
221
|
+
legacy naming context where a function name might be mistaken for a provider.
|
|
222
|
+
|
|
223
|
+

|
|
224
|
+
|
|
225
|
+
*A source-derived sequence view. Every arrow represents a direct Graphify
|
|
226
|
+
`calls` or `invokes` relationship; no runtime request, timing, or trace data
|
|
227
|
+
is implied.*
|
|
228
|
+
|
|
229
|
+
### Section 2 — Project explanation
|
|
230
|
+
|
|
231
|
+
- Architecture and component walkthrough.
|
|
232
|
+
- Technology choices and the evidence behind them.
|
|
233
|
+
- Trade-offs, alternatives, strengths, and costs.
|
|
234
|
+
- Related diagram components for each section.
|
|
235
|
+
- Confirmed versus inferred labels, plus optional author questions for
|
|
236
|
+
unresolved, load-bearing rationale.
|
|
237
|
+
|
|
238
|
+
## Evidence rules
|
|
239
|
+
|
|
240
|
+
Graphitect keeps the distinction between repository fact and analysis visible:
|
|
241
|
+
|
|
242
|
+
- **Confirmed**: backed by code, README, docs, Git history, or a direct author
|
|
243
|
+
answer. File-backed citations must contain the cited phrase.
|
|
244
|
+
- **Inferred**: a reasoned interpretation or recommendation. It is useful, but
|
|
245
|
+
never presented as a proven historical decision.
|
|
246
|
+
- Diagram relationships: direct Graphify extraction, not an LLM reconstruction.
|
|
247
|
+
|
|
248
|
+
If `synthesize --non-interactive` or the agent workflow writes
|
|
249
|
+
`graphitect-questions.json`, fill its `answer` fields and rerun with
|
|
250
|
+
`--answers`. Unanswered items remain inferred.
|
|
251
|
+
|
|
252
|
+
## Advanced commands
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# Write reusable Graphify-grounded data.
|
|
256
|
+
graphitect ground /path/to/project -o grounding.json
|
|
257
|
+
|
|
258
|
+
# Synthesize from that data with a configured standalone provider.
|
|
259
|
+
graphitect synthesize grounding.json --repo /path/to/project -o understanding.json
|
|
260
|
+
|
|
261
|
+
# Render a saved understanding file.
|
|
262
|
+
graphitect deliver understanding.json --title "Project name" -o project-architecture
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
For normal use, prefer `graphitect build` or the installed-agent workflow.
|
|
266
|
+
|
|
267
|
+
## Privacy and network behavior
|
|
268
|
+
|
|
269
|
+
- Graphify extraction and diagram generation run locally.
|
|
270
|
+
- The self-contained report embeds its interactive viewer; viewing it requires
|
|
271
|
+
no hosted Graphitect service.
|
|
272
|
+
- Standalone explanation generation sends the bounded evidence context to the
|
|
273
|
+
provider you configure.
|
|
274
|
+
- Installed-agent mode uses the host agent's own model and permissions instead
|
|
275
|
+
of a Graphitect API key.
|
|
276
|
+
|
|
277
|
+
Review your repository and provider policy before sending source context to an
|
|
278
|
+
external model.
|
|
279
|
+
|
|
280
|
+
## Bundled projects and notices
|
|
281
|
+
|
|
282
|
+
Graphitect bundles Graphify under its Apache-2.0 distribution terms and
|
|
283
|
+
Archify under MIT plus its third-party notices. See `licenses/graphify/`,
|
|
284
|
+
`licenses/archify/`, and the root notice files for details.
|