Skip to content

feat(skill): run the pipeline as graphify pipeline subcommands, no inline Python (#197) - #4275

Open
nothariharan wants to merge 10 commits into
Graphify-Labs:v8from
nothariharan:fix/197-pipeline-subcommands
Open

nothariharan wants to merge 10 commits into
Graphify-Labs:v8from
nothariharan:fix/197-pipeline-subcommands

Conversation

@nothariharan

@nothariharan nothariharan commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

What this fixes

Closes the remaining work in #197.

The Graphify agent skill delivered every pipeline step — and, on demand, every reference flow — as inline Python inside a bash string:

$(cat graphify-out/.graphify_python) -c "
import json
from graphify.detect import detect
# ... 10-20 lines of Python, with # comments
"

In Claude Code that trips two content-based approval heuristics once per step:

  1. command_substitution — from $(cat graphify-out/.graphify_python).
  2. "Newline followed by # inside a quoted argument" — from the multi-line Python comments.

Neither can be satisfied by permission allow-rules, so a single run cost roughly 30 manual "Yes" clicks and the skill was close to unusable without hand-patching it.

How it's fixed

Every step is now a plain console command. The step bodies live in a new graphify/pipeline.py and are exposed as graphify pipeline <step>:

Old inline block New command
detect(...) + write sidecar graphify pipeline detect <path>
collect_files + extract graphify pipeline extract-ast <path>
empty .graphify_semantic.json graphify pipeline empty-semantic
check_semantic_cache(...) graphify pipeline cache-check <path> --prompt-file SPEC
chunk merge graphify pipeline merge-chunks
save_semantic_cache(...) graphify pipeline save-cache <path> --prompt-file SPEC
cached+new merge graphify pipeline merge-semantic
AST+semantic merge graphify pipeline merge-extraction
build/cluster/analyze/report graphify pipeline build <path> [--directed]
health check graphify pipeline diagnose <path>
curated labels graphify pipeline label <path> --labels '<json>'
manifest + cost graphify pipeline save-manifest <path>
cleanup graphify pipeline cleanup

The on-demand reference flows are converted the same way, with seven more steps plus existing commands:

  • query → graphify pipeline vocab, graphify query, graphify path, graphify explain, graphify save-result
  • update → graphify pipeline detect-incremental | code-only-check | empty-extract | update-merge | graph-diff
  • add / watch → graphify add, graphify watch (now parses --debounce and defaults to the .graphify_root marker)
  • transcribe → graphify pipeline transcribe
  • exports (MCP) → the graphify-mcp console script instead of -m graphify.serve

Because every step is a console-script call, Bash(graphify *) becomes an allowlistable prefix, the cat-to-interpreter indirection disappears, and the security surface shrinks: arguments go through argparse instead of being interpolated into a Python string.

The skill is generated — the fragment is the source of truth

graphify/skill*.md and graphify/skills/*/references/*.md are rendered from tools/skillgen/fragments/ by python -m tools.skillgen. The edits are in the fragments (core/core.md, references/**, query-stub/default.md); the ~200 generated artifacts and the expected/ snapshots are regenerated and blessed (python -m tools.skillgen --bless).

Verification

  • Byte-identical output. The old inline-Python blocks and the new subcommands were run side by side on a real corpus: .graphify_detect.json, .graphify_ast.json, .graphify_semantic.json, .graphify_extract.json, .graphify_analysis.json, graph.json, manifest.json, and GRAPH_REPORT.md are all identical (report modulo its timestamp). Same graph, different delivery.
  • No new test failures. Rebased onto v8 (e8eb76e7, 0.9.89). Full suite in this environment: 7911 passed, 216 skipped, 10 failed; all 10 fail identically on a clean upstream/v8 (3 test_hooks, 1 wheel build, 2 os.getcwd subprocess, 1 @/ alias resolution, 3 test_ingest_url_type Windows symlink readlink), none in code this PR touches.
  • New tests. tests/test_pipeline_cli.py (pipeline steps end to end, including the incremental-update flow, the #479 shrink guard + --force, --no-gitignore, GRAPHIFY_OUT, and the boolean-flag/positional parsing) and tests/test_skill_no_inline_python.py (a drift guard that fails if any split host or reference reintroduces an inline -c block).
  • Reviewed twice by a separate agent; all findings fixed (nested graphify-out from a wrong cache_root, merge-chunks erroring on the all-cached path, --no-gitignore/--force silently dropped, a boolean flag swallowing the following path, non-numeric label keys crashing, GRAPHIFY_OUT ignored, stale fallback prose, and the MCP config caveat).

Known blocker / deliberately out of scope: the aider & devin monoliths

skill-aider.md and skill-devin.md still contain inline Python (37 and 39 -c blocks). This is not a capability gap — it's a deliberately isolated, high-blast-radius change, and it is not what #197 reports (those are Aider and Devin, not Claude Code).

Why they're separate:

  1. They aren't generated from core.md + references. gen.render() returns _read_fragment("core/{aider|devin}.md") verbatim — each is a hand-maintained 1,300–1,400-line single file that duplicates the entire pipeline and every reference flow inline. Converting them is the same work as everything in this PR, repeated twice.

  2. They're frozen against a pinned v8 blob. monolith_roundtrip (tools/skillgen/gen.py:1232) diffs the rendered monolith against roundtrip_ref (a pinned v8 commit) and requires every non-blank changed line to match a predicate in _SANCTIONED_MONOLITH_DIFFS (19 predicates). So a conversion there also has to add a new sanctioned-diff predicate and re-validate the round-trip — the guard exists precisely to stop arbitrary drift, and touching it is a wide, cross-cutting change.

  3. Different hosts. Aider and Devin have their own delivery mechanism; the Claude Code heuristics in Skill should use CLI subcommands instead of inline python -c #197 don't apply to them.

I chose to keep this PR scoped, correct, and low-risk rather than fold a 76-block rewrite of two frozen files into it. The monolith conversion is a clean follow-up PR on its own.

Scope summary

  • ✅ Claude Code skill set (skill.md + skills/claude/references/*): zero inline Python, zero $(cat graphify-out/.graphify_python). Only Step 1's one-time interpreter detection remains (inherent to installing/detecting graphify, and it is a single block, not per-step).
  • ✅ All other split hosts (Codex, Windows, opencode, kilo, copilot, claw, droid, amp, trae, kiro, pi, vscode, agents) and all references: zero non-bootstrap inline -c.
  • ⏭️ aider/devin monoliths: unchanged, tracked as a follow-up (see above).

Ref #114 (which fixed only the save_query_result block).

@github-actions

Copy link
Copy Markdown

Thanks for the pull request, @nothariharan. A maintainer will review it soon.

Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions.

A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic.

@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.

Formal verification could not match the changed code to the code graph, so it may not have checked the code this PR changed.

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

Not checked: tests were not run; formal verification proved 0 of 1 changed function(s) (1 not verified).

Formal verification. PR-changed functions: 0/1 verified (0 proven, 0 may-equivalent, 0 distinguished) · 1 not verified (1 vacuous).

Not verified on this run: dispatch\_command (vacuous: never exercised).


Graphify review — findings

Adds a graphify pipeline <step> command that exposes each stage of the agent skill as a plain CLI step: detect, AST and semantic extraction with cache hits/misses, merging, build, the read-only diagnose health gate, labeling, manifest/cost tracking, cleanup, plus the query, transcribe and incremental-update steps. The generated skill files for every agent call these steps instead of inline python -c blocks, so they no longer need interpreter path substitution. Step sidecars default to the cwd, and boolean flags like --no-gitignore and --directed never swallow the following path.

Worth a look

  • step_label writes the report and labels before the shrink-guard can refuse — graphify/pipeline.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review

Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 2073 functions depend on the 1834 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: dispatch_command() — 2 callers, 131 callees
  • new: _cmd_pipeline() — 1 callers, 23 callees
  • new: step_build() — 1 callers, 13 callees
  • new: step_label() — 1 callers, 9 callees
  • new: step_extract_ast() — 1 callers, 7 callees
  • new: step_save_manifest() — 1 callers, 7 callees
  • new: step_update_merge() — 1 callers, 7 callees
  • new: step_graph_diff() — 1 callers, 6 callees
  • …and 1 more — each is listed as a finding

Verification — 2073 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: 2005 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

357 of 357 test file(s) selected (100%) via static blast radius.

Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.

  • tests/test_affected_cli.py — impact, full-run-safety
  • tests/test_affected_member_seed.py — full-run-safety
  • tests/test_agents_platform.py — impact, full-run-safety
  • tests/test_analyze.py — full-run-safety
  • tests/test_anthropic_custom_endpoint.py — full-run-safety
  • tests/test_antigravity_install.py — full-run-safety
  • tests/test_apm_fallback_version.py — full-run-safety
  • tests/test_architecture_doc.py — full-run-safety
  • tests/test_astro_extraction.py — full-run-safety
  • tests/test_astro_import_ids.py — full-run-safety
  • tests/test_atomic_canvas_export.py — full-run-safety
  • tests/test_atomic_version_stamp.py — full-run-safety
  • tests/test_atomic_writes.py — full-run-safety
  • tests/test_backend_env_isolation.py — full-run-safety
  • tests/test_backend_extras.py — full-run-safety
  • tests/test_benchmark.py — full-run-safety
  • tests/test_benchmark_raw_graph.py — full-run-safety
  • tests/test_blade_extractor.py — full-run-safety
  • tests/test_build.py — full-run-safety
  • tests/test_build_located_semantic_identity.py — full-run-safety
  • tests/test_build_merge_dedup_scope.py — full-run-safety
  • tests/test_build_merge_hyperedges_and_prune.py — full-run-safety
  • tests/test_build_merge_shrink_guard.py — full-run-safety
  • tests/test_builtin_global_type_refs.py — full-run-safety
  • tests/test_cache.py — full-run-safety
  • tests/test_cache_stale_import_target.py — full-run-safety
  • tests/test_callflow_html.py — full-run-safety
  • tests/test_cargo_introspect.py — full-run-safety
  • tests/test_cargo_missing_manifest.py — full-run-safety
  • tests/test_carried_hyperedge_remap.py — full-run-safety
  • tests/test_case_sensitive_resolution.py — full-run-safety
  • tests/test_charmap_encoding.py — full-run-safety
  • tests/test_chunking.py — full-run-safety
  • tests/test_cjs_module_extension.py — full-run-safety
  • tests/test_claude_cli_backend.py — full-run-safety
  • tests/test_claude_md.py — full-run-safety
  • tests/test_cli_broken_pipe.py — full-run-safety
  • tests/test_cli_export.py — full-run-safety
  • tests/test_cli_help.py — full-run-safety
  • tests/test_cloud_cta.py — impact, full-run-safety
  • tests/test_cluster.py — full-run-safety
  • tests/test_cluster_ambiguous_scale.py — full-run-safety
  • tests/test_cluster_exclude_hubs.py — full-run-safety
  • tests/test_cobol_extractor.py — full-run-safety
  • tests/test_codebuddy.py — impact, full-run-safety
  • tests/test_community_hub_labels.py — full-run-safety
  • tests/test_community_labels_skill.py — impact, changed-test, full-run-safety
  • tests/test_confidence.py — full-run-safety
  • tests/test_corrupt_graph_json.py — full-run-safety
  • tests/test_cpp_method_declarations.py — full-run-safety
  • … and 307 more

non-code file(s) changed (graphify/skill-agents.md, graphify/skill-amp.md, graphify/skill-claw.md, graphify/skill-codex.md, graphify/skill-copilot.md …) → running the full suite for safety (a code graph can't see config/fixture/data deps)

changed code file(s) with no mapped test (graphify/skill-agents.md, graphify/skill-amp.md, graphify/skill-claw.md, graphify/skill-codex.md, graphify/skill-copilot.md …) — a coverage gap or a missing link — running the full suite rather than only the selected tests

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Docs that may be stale (advisory)

…and 10 more.

Formal verification

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: no capturable inputs from the test suite; property tier: not verifiable: all 40 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)

· 9 grounded finding(s) anchored inline below.

Comment thread graphify/cli.py
return "\n".join(lines)


def _cmd_pipeline(argv: list[str]) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — _cmd_pipeline()

fans out to 23 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/cli.py
sys.exit(1)


def dispatch_command(cmd: str) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — dispatch_command()

fans out to 131 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/pipeline.py
# --------------------------------------------------------------------------


def step_extract_ast(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — step_extract_ast()

fans out to 7 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/pipeline.py
# --------------------------------------------------------------------------


def step_merge_chunks(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — step_merge_chunks()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/pipeline.py
# --------------------------------------------------------------------------


def step_build(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — step_build()

fans out to 13 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/pipeline.py
# --------------------------------------------------------------------------


def step_label(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — step_label()

fans out to 9 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/pipeline.py
# --------------------------------------------------------------------------


def step_save_manifest(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — step_save_manifest()

fans out to 7 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/pipeline.py
return {"created": True}


def step_update_merge(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — step_update_merge()

fans out to 7 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/pipeline.py
}


def step_graph_diff(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression — step_graph_diff()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

@safishamsi

Copy link
Copy Markdown
Member

Thanks for this, @nothariharan - the motivation is spot on (the inline $(cat ...) -c "..." blocks trip Claude Code's approval heuristics on nearly every step and can't be allowlisted), and the graphify pipeline <step> subcommands with argparse are a clean, safer replacement. The new pipeline.py/CLI code is solid on its own and the suite passes.

It needs a rebase before it can land, though - the branch predates two fixes now on the default branch, and the refactor has to carry them forward:

  1. Port the _origin='semantic' stamping (required - correctness). The default branch now stamps _origin='semantic' on all semantic nodes/edges before build (this is the Skill Part C never stamps _origin, so graphify update deletes the semantic layer of any doc without section numbers #2843 fix). step_merge_extraction doesn't do that, so a semantic node whose source_location looks like L<line> gets mis-tiered as AST and the next graphify update deletes it. Please stamp in step_merge_extraction (you can reuse graphify.llm._stamp_semantic_origin).
  2. Reconcile the stamping test. tests/test_semantic_origin_stamp.py::test_part_c_stamps_the_semantic_side currently parses the inline Part C -c block you're removing, so it'll fail after rebase. Please rewrite it to exercise graphify pipeline merge-extraction / step_merge_extraction directly.
  3. Keep the explicit root= anchor. step_extract_ast passes only cache_root=; the default branch's AST step now passes root=Path('INPUT_PATH') explicitly (extract(): cache_root without root re-anchors every AST node id, and the node-count shrink guard cannot notice #3727). Please pass root= too (and consider aligning cache_root with the --out dir the way step_detect does).
  4. Rebase + regenerate. Resolve the two fragment conflicts (core/core.md, references/shared/update.md) and re-run python -m tools.skillgen --bless so the generated artifacts match; cli.py/pipeline.py merge cleanly.

Happy to re-review once it's rebased and green. Really want to get this one in.

@nothariharan
nothariharan force-pushed the fix/197-pipeline-subcommands branch from 465248a to c65bcb4 Compare October 13, 2026 13:11
@nothariharan

Copy link
Copy Markdown
Contributor Author

Rebased onto v8 (e8eb76e7, 0.9.89) and carried the review points forward. No more conflicts.

The tests that parsed the removed inline blocks now exercise the pipeline steps they dispatch to: test_semantic_origin_stamp (step_merge_extraction), test_skill_part_a_explicit_root (step_extract_ast), and test_skill_codex_semantic_merge (B0/B3/Part C steps). Regenerated skills with python -m tools.skillgen and re-blessed expected/; python -m tools.skillgen --check is clean.

Full suite: 7911 passed, 216 skipped, 10 failed. All 10 fail identically on a clean upstream/v8 checkout in this environment (3 test_hooks, 1 wheel build, 2 os.getcwd subprocess, 1 @/ alias resolution, 3 test_ingest_url_type Windows symlink readlink). None touch code this PR changes.

Ref #197.

@nothariharan
nothariharan force-pushed the fix/197-pipeline-subcommands branch 2 times, most recently from 0a6e145 to 09f3143 Compare October 16, 2026 01:29
@nothariharan

Copy link
Copy Markdown
Contributor Author

Rebased again onto v8 (10130e79, 0.9.91). No conflicts this time.

One upstream test added since the last rebase needed adapting: test_query_fallback_edges parsed the inline NetworkX fallback in references/query/default.md, which this PR removes. Retargeted it at the code the split hosts now use, graphify.serve (_query_graph_text -> _bfs/_dfs -> _complete_induced_edges -> _subgraph_to_text). The guarantees it held are unchanged: seed-to-seed edges, cycles, cross-links, undirected dedup, and the depth and budget limits. The multigraph case now documents the renderer's one-relation-per-ordered-pair behaviour instead of asserting three parallel edges.

Full suite: 8045 passed, 216 skipped, 7 failed. All 7 fail identically on a clean upstream/v8 in this environment (3 test_hooks, 1 wheel build, 2 os.getcwd subprocess, 1 @/ alias resolution), none in code this PR touches. skillgen --check and ruff are clean.

Ref #197.

nothariharan and others added 10 commits October 18, 2026 16:10
Graphify-Labs#197)

The agent skill carried each pipeline step as an inline
`$(cat graphify-out/.graphify_python) -c "..."` block. That form trips
Claude Code's command_substitution and "newline followed by #" approval
prompts once per step and cannot be allowlisted, so a run cost ~30 manual
confirmations.

Add `graphify pipeline <step>` so every step is a plain console command:
no inline script, no command substitution, and `Bash(graphify *)` is
allowlistable. The step bodies live in graphify.pipeline and are
transcriptions of the inline blocks they replace, so a run produces the
same graph.json.

Regenerate the skill artifacts from the updated core/shell fragments, and
move the drift, cross-shell parity, and Graphify-Labs#2490 curated-label guards to
follow the flow to the subcommands. The hand-authored aider/devin
monoliths keep their inline pipelines for now.
)

Follow-up fixes to the graphify pipeline steps, found in review:

- detect: pass the directory that CONTAINS graphify-out as cache_root, not
  graphify-out itself, so the stat cache and Google-Workspace conversions are
  not written to a nested graphify-out/graphify-out.
- merge-chunks: write an empty .graphify_semantic_new.json on zero chunks
  instead of erroring, so the all-cached path (which routes through B3) still
  produces the sidecar Part C reads unconditionally (Graphify-Labs#1392).
- empty-semantic: return fresh lists per call rather than sharing module state.
- cli: honor --no-gitignore (was silently dropped) and thread --force to
  build/label so the documented Graphify-Labs#479 remediation actually overrides the guard.
- cli: reject non-integer --labels keys with a clean error instead of a
  traceback, and honor --help anywhere after the step.
- out dir: honor the GRAPHIFY_OUT env override like the rest of the CLI (Graphify-Labs#686).
- restore the @@INTERP_GUARD@@ block so the on-demand reference flows that still
  read .graphify_python keep their re-resolve safety net.

Regenerate the skill artifacts.
…phify-Labs#197)

The core pipeline was converted in the prior commit, but the reference flows it
loads on demand (update, query, add/watch, transcribe, exports) still ran
$(cat graphify-out/.graphify_python) -c "...", so /graphify update, /graphify
query, /graphify add, transcription, and the MCP export still triggered the same
Claude Code approval prompts. Convert them too, so the whole Claude Code skill
set is free of inline Python and interpreter substitution.

New pipeline steps: vocab, transcribe, detect-incremental, code-only-check,
empty-extract, update-merge, graph-diff.

Reference rewrites:
- query: vocab step, graphify query/path/explain, graphify save-result;
  the obsolete inline NetworkX traversal fallback (which duplicated the CLI) is
  removed, and the query stub no longer promises it.
- update: detect-incremental / code-only-check / empty-extract / update-merge /
  graph-diff replace the six inline blocks.
- add-watch: graphify add, graphify watch (which now parses --debounce and
  defaults to the .graphify_root marker instead of the cwd).
- transcribe: the transcribe step.
- exports: graphify-mcp console script instead of -m graphify.serve.

The drift guard now also covers graphify/skills/*/references/*.md, so a future
inline block in any split host fails the test.
…abs#197)

- cli: boolean pipeline flags (--directed/--force/--no-gitignore/
  --google-workspace) no longer consume the next token, so
  detect --no-gitignore <path> scans the corpus instead of the cwd.
- cli: watch --debounce with no value errors instead of silently defaulting.
- query reference: drop stale prose about the removed inline fallback.
- exports reference: note the absolute-interpreter fallback for a GUI Claude
  Desktop that lacks graphify-mcp on PATH.
- tests: cover the boolean-flag ordering and the watch debounce error.
…Graphify-Labs#197, Graphify-Labs#4240)

The split hosts no longer carry an inline detect block, so the Graphify-Labs#4240 guard now
exercises graphify.pipeline.step_detect / step_detect_incremental, and the
monoliths' remaining inline blocks are still executed. Same contract, new path.
…raphify-Labs#197)

Rebasing onto v8 surfaced correctness fixes the default branch added after
the branch was cut, plus merge-only pipeline work the rebase dropped:

- step_merge_extraction now stamps _origin='semantic' on the semantic side
  before merging (reuses llm._stamp_semantic_origin), so a line-located doc
  node is not mis-tiered as AST and deleted by the next `graphify update`
  (Graphify-Labs#2843).
- step_extract_ast passes `root=` explicitly -- `cache_root` alone
  re-anchors every AST node id, which the node-count shrink guard cannot see
  (Graphify-Labs#3727) -- and aligns `cache_root` with `--out` the way step_detect does.
- Restore `_persisted_corpus_shaping` in step_detect / step_detect_incremental
  (Graphify-Labs#4240); it lived only in the dropped merge commit.
- `detect-incremental` prints the per-type breakdown (`new_by_type`)
  instead of dumping the corpus into the agent context (Graphify-Labs#3944).

Tests that parsed the removed inline Part A / Part C / B3 blocks now exercise
the pipeline steps they dispatch to: test_semantic_origin_stamp,
test_skill_part_a_explicit_root, test_skill_codex_semantic_merge.

Regenerated skills (`python -m tools.skillgen`) and re-blessed expected/
snapshots; `--check` is clean.

Co-Authored-By: opencode <noreply@opencode.ai>
…raphify-Labs#197)

The query reference fragment no longer carries an inline NetworkX fallback
(Graphify-Labs#197): the split hosts call `graphify query`, whose traversal lives in
graphify.serve (_query_graph_text -> _bfs/_dfs -> _complete_induced_edges ->
_subgraph_to_text). Repoint the regression tests at that path. The guarantees
that survive are unchanged (seed-to-seed edges, cycles, cross-links,
undirected dedup, depth and budget limits); the renderer's
one-relation-per-ordered-pair behaviour for multigraphs is documented rather
than asserted as three parallel edges.

Co-Authored-By: opencode <noreply@opencode.ai>
…-Labs#197)

python -m tools.skillgen (render) + --bless. The regenerated update references
carry the code-only wording and the Pi dispatch fragment (pi-subagents) that
landed on v8 since 0.9.91. --check is clean.

Co-Authored-By: opencode <noreply@opencode.ai>
…raphify-Labs#197)

v8 commit 3ab2cba made _subgraph_to_text render every parallel relation, so
the retargeted guard now expects all three (calls/imports forward, references
back) instead of two.

Co-Authored-By: opencode <noreply@opencode.ai>
…he CLI (Graphify-Labs#197)

test_skill_code_only_incremental_update parsed the inline Part A/Part C/update
-c blocks, which Graphify-Labs#197 replaced with graphify pipeline subcommands; it now runs
those subcommands against the same clean intermediate directory.
test_skill_no_backtick_substitution's finder guard now expects only the
aider/devin monoliths to carry an inline -c Part C / --update merge.

Co-Authored-By: opencode <noreply@opencode.ai>
@nothariharan
nothariharan force-pushed the fix/197-pipeline-subcommands branch from 09f3143 to 79fd268 Compare October 18, 2026 11:17
@nothariharan

Copy link
Copy Markdown
Contributor Author

Rebased again onto v8 (86c57be8, 0.9.92). A rebase was required: the branch was still on 0.9.91, 35 commits behind.

Upstream fragment changes carried through the conflict resolution (not dropped):

  • core.md @@WRITER_AGENT@@ / @@WRITER_AGENT_ARG@@ placeholders (Pi dispatch).
  • update.md code-only wording (run Part B's Fast path plus Part C, skip B0-B3).
  • exports.md neo4j/falkordb push URI handling.
  • the new dispatch/pi-subagents.md fragment.

Upstream tests added since 0.9.91 asserted on the inline -c blocks this PR removes, so they were adapted:

  • test_query_fallback_edges: retargeted at graphify.serve; the multigraph case now expects all parallel relations (upstream 3ab2cbab).
  • test_skill_code_only_incremental_update: now drives the pipeline subcommands against its clean intermediate directory.
  • test_skill_no_backtick_substitution: the finder guard now expects only the aider/devin monoliths to still carry an inline -c Part C / --update merge.

Every commit in the branch is free of conflict markers (checked across all 10). Regenerated skills and re-blessed expected/; skillgen --check and ruff clean.

The only remaining local failures are 9 that fail identically on a clean upstream/v8 (86c57be8) in this environment: 3 test_hooks, 1 wheel build, 2 os.getcwd subprocess, 1 @/ alias resolution, and 2 test_code_only_update_all_hosts monolith cases (bash plus a Windows interpreter path). None are in code this PR touches. CI is running and I am watching.

Ref #197.

@FolatheDuckofDuckingburg FolatheDuckofDuckingburg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Adds a graphify pipeline command that exposes each stage of the agent skill as a plain CLI step: detect, AST and semantic extraction with cache hits/misses, merging, build, the read-only diagnose health gate, labeling, manifest/cost tracking, cleanup, plus the query, transcribe and incremental-update steps. The generated skill files for every agent call these steps instead of inline python -c blocks, so they no longer need interpreter path substitution. Step sidecars default to the cwd, and boolean flags like --no-gitignore and --directed never swallow the following path.

This branch has not been deployed

No deployments
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.

3 participants