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,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."
|