Skip to content

feat: Docker/Podman containerized setup with GHCR publishing (closes #1) - #2743

Open
slmingol wants to merge 4 commits into
Graphify-Labs:v8from
slmingol:v8
Open

feat: Docker/Podman containerized setup with GHCR publishing (closes #1)#2743
slmingol wants to merge 4 commits into
Graphify-Labs:v8from
slmingol:v8

Conversation

@slmingol

@slmingol slmingol commented Aug 15, 2026

Copy link
Copy Markdown

Summary

  • Add .github/workflows/docker.yml — builds linux/amd64 + linux/arm64 images via native runners (no QEMU) on push to v8 and on release; pushes to ghcr.io/graphify-labs/graphify with :latest, semver, and :sha- tags; uses GHA layer cache for fast incremental rebuilds
  • Add docker-compose.yaml — two services: graphify (CLI indexing, profile:cli) and mcp (HTTP MCP server); prefers the GHCR image when present, falls back to local build:; supports GRAPHIFY_API_KEY, GRAPHIFY_PORT, GRAPHIFY_IMAGE env vars; SELinux :Z guidance in comments; TCP socket healthcheck (avoids SSE framing false negatives)
  • Add Makefile — auto-detects docker vs podman; targets: pull, build, up, down, index [SRC=...], logs; up and index auto-pull from GHCR, fall back to local build
  • Update Dockerfile — generalize entrypoint from python -m graphify.serve to graphify CLI; graphify-mcp still reachable via --entrypoint; pin mcp<2.0.0 (2.0.0 removed mcp.types.AnyUrl used by graphify.serve) and cryptography<42 (42+ Rust _openssl binding crashes with SIGILL on ARM64 container runtimes)
  • Update README.md — expand container section with GHCR pull, make quick start, compose and bare docker/podman examples, Podman/SELinux notes

Test plan

  • podman build succeeds locally (tested on Apple Silicon)
  • podman compose config parses docker-compose.yaml without errors
  • podman run --rm graphify --help and podman run --rm --entrypoint graphify-mcp graphify --help both work
  • GHA workflow (docker.yml) ran green on push: build + push linux/amd64 + linux/arm64 in 3m 48s
  • make pull && make index && GRAPHIFY_API_KEY=x make up — end-to-end smoke test (graphify extract /src --code-only --output /data + MCP server starts on :8080)

Notes for maintainers

  • mcp<2.0.0 pin is a workaround — graphify.serve imports from mcp.types import AnyUrl which was removed in mcp 2.0.0. The HTTP transport needs updating for mcp 2.x compatibility.
  • cryptography<42 pin avoids the Rust _openssl binding (introduced in 42) that crashes with SIGILL in ARM64 container runtimes (podman on Apple Silicon). Should be revisited when upstream fixes the runtime compatibility.

🤖 Generated with Claude Code

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 7 change(s) tested, no difference found (not proven).


Graphify review — findings

This PR adds a new GitHub Actions workflow (.github/workflows/docker.yml) that builds multi-arch (amd64/arm64) Docker images on native runners and pushes them to GHCR as a merged manifest. It also rewrites the ARCHITECTURE.md pipeline/module documentation to describe a simplified, single-function-per-stage API (e.g. build_graph, analyze, render_report, export, start_server) and trims older content. The changed-symbols list further suggests accompanying edits across many test files, extractors, skill/tooling fragments, and the changelog. Note: the diff was truncated, so the full surface area (especially the many listed test and extractor symbols) isn't visible here.

No blocking issues surfaced. 2 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 6784 functions depend on the 5529 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _find_node() — 13 callers, 3 callees
  • worse: _emit_rescued_import() — 3 callers, 4 callees

Verification — 6784 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 6760 function(s) in the blast radius were not formally verified this run

Formal verification

No difference found (not proven): No behavior difference found in resolve\_seed (not a proof).

The verifier ran both versions of resolve\_seed on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in \_query\_subgraph\_tokens (not a proof).

The verifier ran both versions of \_query\_subgraph\_tokens on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify \_abs\_identity.

The verifier did not have enough to check \_abs\_identity, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: non-vacuity: domain too small (only 2 distinct inputs exercised, need 3) — 'no divergence' would be near-vacuous

Could not verify: Could not verify build.

The verifier did not have enough to check build, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 9 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly AttributeError — names the real obstacle, not a sampling gap)

Could not verify: Could not verify build\_from\_json.

The verifier did not have enough to check build\_from\_json, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 6 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly NameError — names the real obstacle, not a sampling gap)

Could not verify: Could not verify build\_merge.

The verifier did not have enough to check build\_merge, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `str | Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify graph\_has\_legacy\_ids.

The verifier did not have enough to check graph\_has\_legacy\_ids, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `str | Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_infer\_merge\_root.

The verifier did not have enough to check \_infer\_merge\_root, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_load\_existing\_graph.

The verifier did not have enough to check \_load\_existing\_graph, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify merge\_raw\_extraction.

The verifier did not have enough to check merge\_raw\_extraction, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `str | Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in \_norm\_source\_file (not a proof).

The verifier ran both versions of \_norm\_source\_file on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in \_normalize\_hyperedge\_members (not a proof).

The verifier ran both versions of \_normalize\_hyperedge\_members on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify prefix\_graph\_for\_global.

The verifier did not have enough to check prefix\_graph\_for\_global, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 115 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous

No difference found (not proven): No behavior difference found in \_semantic\_id\_remap (not a proof).

The verifier ran both versions of \_semantic\_id\_remap on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify cached\_word\_count.

The verifier did not have enough to check cached\_word\_count, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify check\_semantic\_cache.

The verifier did not have enough to check check\_semantic\_cache, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify file\_hash.

The verifier did not have enough to check file\_hash, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify load\_cached.

The verifier did not have enough to check load\_cached, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_relativize\_source\_files\_in.

The verifier did not have enough to check \_relativize\_source\_files\_in, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify save\_cached.

The verifier did not have enough to check save\_cached, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in generate\_call\_table\_rows (not a proof).

The verifier ran both versions of generate\_call\_table\_rows on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in \_node\_link\_payload (not a proof).

The verifier ran both versions of \_node\_link\_payload on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify write\_callflow\_html.

The verifier did not have enough to check write\_callflow\_html, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project` is annotated `str | Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify dispatch\_command.

The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_stamped\_manifest\_files.

The verifier did not have enough to check \_stamped\_manifest\_files, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

· 2 more finding(s) on lines outside this diff (see the check run).

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 7 change(s) tested, no difference found (not proven).


Graphify review — findings

This PR appears to focus on Docker packaging, documentation, and a range of extractor/pipeline behavior changes across the graphify library. - Adds a new GitHub Actions workflow (.github/workflows/docker.yml) that builds native linux/amd64 and linux/arm64 images, pushes per-platform digests to GHCR, and merges them into a single multi-arch manifest with tagging logic. - Rewrites ARCHITECTURE.md to describe a simplified single-function-per-stage pipeline and updated module signatures, and touches CHANGELOG.md (including version/changelog entries). - Changes span many library modules (watch, install, cache, extract, callflow HTML, security, dedup, resolution, skill definitions) plus their corresponding test files, indicating adjustments to extraction/resolution behavior, skill generation, and related test expectations. Surface area is broad, covering CI, docs, core extractor logic, and tests; a reviewer should verify the doc/module-signature claims against the actual code since the rewritten architecture doc diverges from some previously documented signatures.

No blocking issues surfaced. 1 lower-confidence candidate did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 6784 functions depend on the 5529 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _find_node() — 13 callers, 3 callees
  • worse: _emit_rescued_import() — 3 callers, 4 callees

Verification — 6784 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 6760 function(s) in the blast radius were not formally verified this run

Formal verification

No difference found (not proven): No behavior difference found in resolve\_seed (not a proof).

The verifier ran both versions of resolve\_seed on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in \_query\_subgraph\_tokens (not a proof).

The verifier ran both versions of \_query\_subgraph\_tokens on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify \_abs\_identity.

The verifier did not have enough to check \_abs\_identity, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: non-vacuity: domain too small (only 2 distinct inputs exercised, need 3) — 'no divergence' would be near-vacuous

Could not verify: Could not verify build.

The verifier did not have enough to check build, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 9 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly AttributeError — names the real obstacle, not a sampling gap)

Could not verify: Could not verify build\_from\_json.

The verifier did not have enough to check build\_from\_json, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 6 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly NameError — names the real obstacle, not a sampling gap)

Could not verify: Could not verify build\_merge.

The verifier did not have enough to check build\_merge, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `str | Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify graph\_has\_legacy\_ids.

The verifier did not have enough to check graph\_has\_legacy\_ids, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `str | Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_infer\_merge\_root.

The verifier did not have enough to check \_infer\_merge\_root, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_load\_existing\_graph.

The verifier did not have enough to check \_load\_existing\_graph, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify merge\_raw\_extraction.

The verifier did not have enough to check merge\_raw\_extraction, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `graph_path` is annotated `str | Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in \_norm\_source\_file (not a proof).

The verifier ran both versions of \_norm\_source\_file on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in \_normalize\_hyperedge\_members (not a proof).

The verifier ran both versions of \_normalize\_hyperedge\_members on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify prefix\_graph\_for\_global.

The verifier did not have enough to check prefix\_graph\_for\_global, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 115 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous

No difference found (not proven): No behavior difference found in \_semantic\_id\_remap (not a proof).

The verifier ran both versions of \_semantic\_id\_remap on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify cached\_word\_count.

The verifier did not have enough to check cached\_word\_count, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify check\_semantic\_cache.

The verifier did not have enough to check check\_semantic\_cache, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify file\_hash.

The verifier did not have enough to check file\_hash, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify load\_cached.

The verifier did not have enough to check load\_cached, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_relativize\_source\_files\_in.

The verifier did not have enough to check \_relativize\_source\_files\_in, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify save\_cached.

The verifier did not have enough to check save\_cached, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in generate\_call\_table\_rows (not a proof).

The verifier ran both versions of generate\_call\_table\_rows on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in \_node\_link\_payload (not a proof).

The verifier ran both versions of \_node\_link\_payload on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify write\_callflow\_html.

The verifier did not have enough to check write\_callflow\_html, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `project` is annotated `str | Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify dispatch\_command.

The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_stamped\_manifest\_files.

The verifier did not have enough to check \_stamped\_manifest\_files, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

· 2 more finding(s) on lines outside this diff (see the check run).

slmingol and others added 3 commits August 14, 2026 23:29
 #1)

- docker-compose.yaml: two services — graphify (CLI indexing, profile:cli)
  and mcp (HTTP MCP server); prefers ghcr.io/graphify-labs/graphify:latest
  when present, falls back to local build; GRAPHIFY_API_KEY/PORT/IMAGE env
  vars; SELinux :Z guidance; TCP socket healthcheck (avoids SSE 406 false
  negatives); user:0 for podman rootless bind-mount compat
- Makefile: auto-detects docker vs podman (RUNTIME override); targets:
  pull, build, up, down, index [SRC=...], logs; up/index try GHCR pull
  first, fall back to local build; mkdir -p graphify-out guard
- .github/workflows/docker.yml: native runners (ubuntu-latest for amd64,
  ubuntu-24.04-arm for arm64) — avoids broken QEMU cross-compiled C
  extensions; pushes :latest, semver, and :sha- tags; GHA layer cache

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Expand the "Shared HTTP server" section with a new "Running in a
container" subsection covering: GHCR pull (no local Python install),
make quick start, docker/podman compose examples, bare docker/podman
commands, Podman rootless and SELinux notes, GRAPHIFY_IMAGE override.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change entrypoint from python -m graphify.serve to graphify CLI so
  the image serves both indexing (graphify extract) and the MCP server
  (graphify-mcp via --entrypoint); CMD defaults to --help
- Pin mcp<2.0.0: mcp 2.0.0 removed mcp.types.AnyUrl which
  graphify.serve imports for the HTTP transport (ImportError at startup)
- Pin cryptography<42: cryptography 42+ ships a Rust _openssl binding
  that crashes with SIGILL (exit 132) on ARM64 container runtimes
  (podman on Apple Silicon); 41.x is cffi-based and unaffected

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.


Graphify review — findings

This PR adds container-based distribution for graphify. It introduces a GitHub Actions workflow that builds and pushes multi-arch (amd64/arm64) Docker images to GHCR on native runners, a Makefile and docker-compose.yaml for running builds/indexing/the MCP server via Docker or Podman, and modifies the Dockerfile (new entrypoint, pinned mcp<2.0.0 and cryptography deps, general-purpose usage). The README is updated with a new "Running in a container" section documenting the make, compose, and bare docker/podman workflows.

Worth a look

  • Docker image entrypoint no longer starts the MCP serverDockerfile:44 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review Execution auto-disposal is off for this run; enable it (with sandbox isolation) to have Graphify try to confirm or refute this automatically.
  • Docker CMD changed from server launch to --help breaks existing run invocationsDockerfile:44 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review Execution auto-disposal is off for this run; enable it (with sandbox isolation) to have Graphify try to confirm or refute this automatically.
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 27 functions depend on the 27 functions this change touches.

Health — grade A; no new coupling hotspots.

Verification — 27 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 27 function(s) in the blast radius were not formally verified this run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant