Skip to content

fix(skillgen): quote .graphify_python in reference fragments for paths with spaces - #2905

Open
santhiprakash wants to merge 7 commits into
Graphify-Labs:v8from
santhiprakash:fix/quote-graphify-python-in-references
Open

fix(skillgen): quote .graphify_python in reference fragments for paths with spaces#2905
santhiprakash wants to merge 7 commits into
Graphify-Labs:v8from
santhiprakash:fix/quote-graphify-python-in-references

Conversation

@santhiprakash

Copy link
Copy Markdown
Contributor

Problem

tools/skillgen/fragments/references/ render bash snippets with unquoted command substitution $(cat graphify-out/.graphify_python). Bash word-splits the path, so every query/update/add-watch/exports/transcribe step fails on Windows when the cached interpreter path contains a space (e.g. C:\Users\Jane Doe\...).

graphify/skill-windows.md was already migrated to the space-safe PowerShell reader & (Get-Content graphify-out\.graphify_python), but the shared reference fragments were not.

Fixes #2856

Fix

Quote the substitution as "$(cat graphify-out/.graphify_python)" in the five reference source fragments (18 call sites):

  • references/query/default.md (8)
  • references/shared/update.md (6)
  • references/shared/add-watch.md (2)
  • references/shared/transcribe.md (1)
  • references/shared/exports.md (1)

Regenerated all platform graphify/skills/*/references/ artifacts and updated tools/skillgen/expected/ baselines via python3 -m tools.skillgen + --bless.

Test

  • python3 -m tools.skillgen --check — OK (134 artifacts match committed output and expected/)
  • python3 -m pytest tests/test_skillgen.py -q — 63 passed, 1 failed (test_no_version_or_timestamp_in_output false-positive on the literal "unknown" default in query.md; pre-existing on v8, unrelated to this diff)

@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 5 advisory finding(s) below merit a look before merge.


Graphify review — findings

Quote $(cat graphify-out/.graphify_python) in every skill reference doc across all agent variants (agents, amp, claude, codex, copilot, droid, kilo, kiro, opencode, pi, trae, vscode, windows) and their skillgen expected fixtures. Fixes command failures when the resolved Python interpreter path contains spaces.

Worth a look

  • Verbatim question interpolation in shell command enables injectiongraphify/skills/vscode/references/query.md:171 · 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.
  • User-controlled save-result arguments are interpolated into a shell commandgraphify/skills/windows/references/query.md:171 · 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.
  • Verbatim user question is interpolated into a shell command inside double quotesgraphify/skills/claw/references/query.md:171 · 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.
  • Verbatim question is interpolated into a shell command inside double quotesgraphify/skills/copilot/references/query.md:168 · 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.
  • Quoting .graphify_python rejects multi-word interpreter commandsgraphify/skills/kilo/references/query.md:14 · 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 — 754 functions depend on the 754 functions this change touches.

Health — grade A; no new coupling hotspots.

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

santhiprakash added a commit to santhiprakash/graphify that referenced this pull request Aug 21, 2026
The Graphify reviewer flagged five advisory findings on PR Graphify-Labs#2905: the
save-result template at the end of every skill's query.md interpolates the
user's verbatim question and answer into a shell command inside double
quotes. A question like `hello"; rm -rf /` could escape the argument and
break out of the command.

Switch the user-supplied values to single quotes (literal in bash, no
expansion) and document the standard `'\\''` escape pattern for embedded
single quotes. Keep the double-quoted `"\$(cat ...)"` around
.graphify_python: the file is documented to hold a single executable
path, not a multi-word command, so the multi-word-command concern from
the kilo finding is a false positive.

Touched via the central source fragment
`tools/skillgen/fragments/references/query/default.md`; all 14 split
platform references and the expected/ fixtures were regenerated with
`python3 -m tools.skillgen --bless`.

- tools/skillgen --check: 134 artifacts OK
- pytest tests/test_skillgen.py: 64 passed
@santhiprakash
santhiprakash force-pushed the fix/quote-graphify-python-in-references branch from 21018d0 to 5a34411 Compare August 21, 2026 05:14
@santhiprakash

Copy link
Copy Markdown
Contributor Author

Addressing the 5 advisory findings from graphify-labs on 2026-08-20:

  • HIGH (vscode:171, windows:171) — verbatim user question/answer interpolated into a shell command inside double quotes. Fixed by switching the user-supplied values to single quotes (literal in bash, no expansion) and documenting the '\\'' escape pattern for embedded single quotes. The double-quoted "\$(cat ...)" around .graphify_python is kept.
  • MEDIUM (claw:171, copilot:168) — same pattern, same fix. The copilot line is 171 in the regenerated file (the 168 in the review was the pre-PR baseline).
  • MEDIUM (kilo:14) — false positive. .graphify_python is documented to hold a single executable path (sys.executable, written at graphify install time), not a multi-word command. The double-quoting protects that path from word-splitting on Windows, which is the exact case this PR is fixing.

Touched via the central source fragment tools/skillgen/fragments/references/query/default.md; all 14 split-platform references and the expected/ fixtures were regenerated with python3 -m tools.skillgen --bless. The same fix is applied to the /graphify path and /graphify explain save-result blocks at lines 249 and 310 of the same file.

  • python3 -m tools.skillgen --check — OK, 134 artifacts match
  • python3 -m pytest tests/test_skillgen.py — 64 passed
  • Branch rebased onto latest v8 (b2cd362).

@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 3 advisory finding(s) below merit a look before merge.


Graphify review — findings

Quotes the $(cat graphify-out/.graphify_python) command substitution across all add-watch, exports, query, transcribe, and update reference docs (and their skillgen expected fixtures) for every agent variant. Switches the save-result query/path/explain examples to single-quoted user-supplied values and documents the '\'' escape, making the token substitution injection-safe. Updates the corresponding tools/skillgen expected outputs to match.

Worth a look

  • URL placeholder is embedded in shell-evaluated Python sourcegraphify/skills/kilo/references/add-watch.md:14 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • save-result substitution remains injection-prone despite single-quote guidancegraphify/skills/amp/references/query.md:174 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Command injection via unquoted NODE_A/NODE_B/NODE_NAME/QUESTION placeholders still remaininggraphify/skills/opencode/references/query.md:168 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

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

Health — grade A; no new coupling hotspots.

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

santhiprakash added a commit to santhiprakash/graphify that referenced this pull request Aug 22, 2026
Follow-up to Graphify-Labs#2905 addressing three new Graphify advisory findings on the
post-fix render (review at 5a34411):

- HIGH (kilo/references/add-watch.md:14) — URL placeholder embedded in
  shell-evaluated Python source. The 'URL' literal sits inside the
  python -c '...' block, so user-supplied text replaces a Python literal
  rather than flowing through a string parameter. Switching to sys.argv
  reads keeps user text out of evaluated Python source.

- MEDIUM (amp/references/query.md:174, opencode/references/query.md:168) —
  --nodes NODE1 NODE2 left node labels unquoted after the question/answer
  single-quote fix. Node labels from the graph can contain whitespace,
  single quotes, semicolons, or shell metacharacters; substituting them
  unquoted preserves the original command-injection surface. Each node
  label is now single-quoted with the standard '\'' escape documented
  alongside the question/answer pattern.

Same fix applies to all three save-result blocks in the source fragment
(query, path_query, explain) since the unquoted --nodes pattern repeats
across all three.

Source-of-truth fragments edited, then all 14 platform renders +
matching expected/ fixtures regenerated via 'python -m tools.skillgen
--bless'. --check / --audit-coverage / --schema-singleton /
--monolith-roundtrip / --always-on-roundtrip all green; tests/test_skillgen.py
64/64 pass.
@santhiprakash

Copy link
Copy Markdown
Contributor Author

Addressing the 3 new Graphify advisory findings from the re-review at 5a34411:

  • HIGH (kilo/references/add-watch.md:14)'URL' was embedded inside the python -c "..." source as a Python string literal, so user-supplied URLs flowed into evaluated Python source (Python SyntaxError on a URL containing ', and any payload interpreted as Python source). Replaced the literal with url = sys.argv[1] and pass URL/AUTHOR/CONTRIBUTOR as separate shell arguments after the Python source. The shell-arg path treats user text as a string value, not as code.

  • MEDIUM (amp/references/query.md:174, opencode/references/query.md:168)--nodes NODE1 NODE2 left each node label unquoted after the question/answer single-quote fix. Node labels can contain whitespace, single quotes, semicolons, or other shell metacharacters, so substituting them unquoted preserves the original injection surface (sabotage-run verified: a label of user; touch /tmp/INJECTED chained an arbitrary command). Each --nodes argument is now single-quoted with the standard '\'' escape documented alongside the existing question/answer pattern. Same fix applied to the path_query and explain save-result blocks at lines 249 and 310 since the unquoted --nodes pattern repeats across all three.

Source-of-truth fragments edited (tools/skillgen/fragments/references/shared/add-watch.md, tools/skillgen/fragments/references/query/default.md), then all 14 platform renders + matching expected/ fixtures regenerated via python -m tools.skillgen --bless.

Verification:

  • python -m tools.skillgen --check → OK, 134 artifacts match
  • python -m tools.skillgen --audit-coverage → OK
  • python -m tools.skillgen --schema-singleton → OK
  • python -m tools.skillgen --monolith-roundtrip → OK
  • python -m tools.skillgen --always-on-roundtrip → OK
  • python -m pytest tests/test_skillgen.py → 64/64 pass
  • Sabotage run on --nodes NODE1 vs --nodes 'NODE1' confirmed the old pattern chain-evaluates ; as a command separator; the new pattern passes the label as a single string arg.

Head now 12c3b67.

@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 4 advisory finding(s) below merit a look before merge.


Graphify review — findings

Quote $(cat graphify-out/.graphify_python) throughout the graphify skill reference docs so the Python path survives spaces, and rework add-watch.md, query.md, and the save-result snippets to pass user-supplied values (URLs, questions, answers, node labels) as separate sys.argv/single-quoted shell arguments instead of interpolating them into evaluated source. Adds injection-safety guidance covering '\'' escaping for literal single quotes, mirrored across all agent variants (claude, codex, opencode, pi, kiro, trae, droid, claw, windows, vscode, copilot, etc.) and their tools/skillgen expected/fragment fixtures.

Worth a look

  • Whisper prompt export evaluates command substitutionsgraphify/skills/agents/references/transcribe.md:28 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Single-quoted save-result substitution remains command-injectable for questions/answers containing single quotesgraphify/skills/claw/references/query.md:171 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Query save-result docs omit escaping apostrophes in question/answertools/skillgen/expected/graphify__skills__amp__references__query.md:174 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Query save-result quoting guidance leaves question/answer apostrophes unsafetools/skillgen/expected/graphify__skills__copilot__references__query.md:171 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

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

Health — grade A; no new coupling hotspots.

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

@santhiprakash

Copy link
Copy Markdown
Contributor Author

Addressing the 4 new Graphify advisory findings from the re-review at 12c3b67:

  • HIGH (graphify/skills/agents/references/transcribe.md:28) — Whisper prompt export evaluated command substitutions inside the double-quoted export GRAPHIFY_WHISPER_PROMPT="<...>". Replaced with single-quoted assignment plus a separate export line so the prompt stays literal (no expansion of $, , or \\ inside it). Documented the '\'' escape pattern in-line for hints that themselves contain an apostrophe. Same path-safety pattern ("$(cat ...)"`) preserved on the next line.

  • MEDIUM (graphify/skills/claw/references/query.md:171, tools/skillgen/expected/graphify__skills__amp__references__query.md:174, tools/skillgen/expected/graphify__skills__copilot__references__query.md:171) — the prose only documented '\\'' escape for node labels, leaving ORIGINAL_QUESTION and ANSWER without explicit guidance (a question like What's the difference? substituted into 'ORIGINAL_QUESTION' produced a bash syntax error). The escape guidance now names all three substituted values. Sabotage run on the old pattern → unexpected EOF while looking for matching '\''; the new pattern with '\\'' parses cleanly.

Source-of-truth fragments edited (tools/skillgen/fragments/references/shared/transcribe.md, tools/skillgen/fragments/references/query/default.md), then all 14 platform renders + matching expected/ fixtures regenerated.

Verification:

  • python -m tools.skillgen --check → OK, 134 artifacts match
  • python -m tools.skillgen --audit-coverage → OK
  • python -m tools.skillgen --schema-singleton → OK
  • python -m tools.skillgen --monolith-roundtrip → OK
  • python -m tools.skillgen --always-on-roundtrip → OK
  • python -m pytest tests/test_skillgen.py → 64/64 pass
  • Sabotage: old save-result with apostrophe-containing question → bash syntax error; new pattern → parses cleanly. Old double-quoted Whisper export with $(touch ...) injection → executes the command (file created); new single-quoted export → keeps value literal (no file created).

Head now 97bc499.

@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 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

Quote all $(cat graphify-out/.graphify_python) command substitutions and switch save-result/ingest/whisper-prompt invocations to pass user-supplied values as single-quoted sys.argv/shell arguments instead of interpolating them into Python source, closing a shell/Python injection vector in the graphify skill reference docs. Adds guidance on escaping literal single quotes ('\'') across all agent variants (agents, codex, claude, copilot, opencode, droid, etc.) and their skillgen expected-output fixtures.

Worth a look

  • Quoted .graphify_python invocation no longer supports interpreter commands with argumentsgraphify/skills/trae/references/query.md:14 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

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

Health — grade A; no new coupling hotspots.

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

@santhiprakash

Copy link
Copy Markdown
Contributor Author

Acknowledging the 4th re-review (97bc499) — pausing iteration pending maintainer input

The new bot review at 97bc499 flagged one remaining advisory, distinct from the prior rounds:

  • Quoted .graphify_python invocation no longer supports interpreter commands with argumentsgraphify/skills/trae/references/query.md:14 · medium

The bot itself marks this finding "NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review".

Position on the trae finding

.graphify_python is documented across the graphify skill corpus as a single executable path (effectively sys.executable, written at graphify install time into graphify-out/.graphify_python):

  • It is consumed by $(cat graphify-out/.graphify_python) -c "<source>" and $(cat graphify-out/.graphify_python) -m <module> invocations throughout the references.
  • It is never a multi-word command. The install path resolves to one interpreter binary, not python -O or python -m foo.
  • The original bug was that on Windows the unquoted form would word-split on a path with spaces (e.g. C:\Program Files\Python311\python.exe); the fix is exactly the "$(cat ...)" form.

If .graphify_python ever were to hold interpreter arguments, every reference doc in the repo (all 14 platform variants of query.md, add-watch.md, transcribe.md, update.md, exports.md) would need a different shape — xargs, an array-style helper, or a launcher script. None of those are in scope for this PR, which is a quoting fix, not a launcher redesign.

So I'm holding the "$(cat ...)" form as the intentional design and not pushing a 5th commit to "fix" a theoretical regression that the documented use case doesn't exercise.

Status

  • Bot iteration loop: paused. Each prior commit (799220f, 5a34411, 12c3b67, 97bc499) reduced the advisory count from 5 → 3 → 4 → 1 and the residual is a design disagreement the bot itself flags for human review.
  • Verification suite: green as of 97bc499. python -m tools.skillgen --check (134 artifacts), --audit-coverage, --schema-singleton, --monolith-roundtrip, --always-on-roundtrip all OK; pytest tests/test_skillgen.py 64/64 pass.
  • No further commits planned unless a maintainer comments on the trae design or asks me to extend the PR to a launcher.

Happy to walk through any of the four commits on a maintainer review call. Will not push new changes until then.

@santhiprakash

Copy link
Copy Markdown
Contributor Author

Re the residual medium advisory on graphify/skills/trae/references/query.md:14:

Quoted .graphify_python invocation no longer supports interpreter commands with arguments

.graphify_python is written by the interpreter-guard step as sys.executable — a single absolute interpreter path — not a command line with arguments. The double-quoted "$(cat graphify-out/.graphify_python)" form is deliberate: it keeps that path as one shell word when it contains spaces (common with uv tool, pipx, or Windows-style paths). Dropping the quotes to allow word-splitting would re-introduce the original bug this PR fixes (path with spaces breaks into multiple tokens) and would only help a use-case that the file is not intended to hold.

Re-verified on the current head (97bc499):

  • python -m tools.skillgen --check — OK, 134 artifacts match
  • pytest tests/test_skillgen.py — 64 passed

No further code change is needed for this advisory; it's a documented trade-off for the sys.executable invariant. Ready for maintainer review/merge.

…s with spaces

Unquoted $(cat graphify-out/.graphify_python) in shared reference fragments
word-splits on Windows when the cached interpreter path contains a space.
Quote the substitution in the five reference source fragments and regenerate
skill artifacts plus expected/ baselines.

Fixes Graphify-Labs#2856
The Graphify reviewer flagged five advisory findings on PR Graphify-Labs#2905: the
save-result template at the end of every skill's query.md interpolates the
user's verbatim question and answer into a shell command inside double
quotes. A question like `hello"; rm -rf /` could escape the argument and
break out of the command.

Switch the user-supplied values to single quotes (literal in bash, no
expansion) and document the standard `'\\''` escape pattern for embedded
single quotes. Keep the double-quoted `"\$(cat ...)"` around
.graphify_python: the file is documented to hold a single executable
path, not a multi-word command, so the multi-word-command concern from
the kilo finding is a false positive.

Touched via the central source fragment
`tools/skillgen/fragments/references/query/default.md`; all 14 split
platform references and the expected/ fixtures were regenerated with
`python3 -m tools.skillgen --bless`.

- tools/skillgen --check: 134 artifacts OK
- pytest tests/test_skillgen.py: 64 passed
Follow-up to Graphify-Labs#2905 addressing three new Graphify advisory findings on the
post-fix render (review at 5a34411):

- HIGH (kilo/references/add-watch.md:14) — URL placeholder embedded in
  shell-evaluated Python source. The 'URL' literal sits inside the
  python -c '...' block, so user-supplied text replaces a Python literal
  rather than flowing through a string parameter. Switching to sys.argv
  reads keeps user text out of evaluated Python source.

- MEDIUM (amp/references/query.md:174, opencode/references/query.md:168) —
  --nodes NODE1 NODE2 left node labels unquoted after the question/answer
  single-quote fix. Node labels from the graph can contain whitespace,
  single quotes, semicolons, or shell metacharacters; substituting them
  unquoted preserves the original command-injection surface. Each node
  label is now single-quoted with the standard '\'' escape documented
  alongside the question/answer pattern.

Same fix applies to all three save-result blocks in the source fragment
(query, path_query, explain) since the unquoted --nodes pattern repeats
across all three.

Source-of-truth fragments edited, then all 14 platform renders +
matching expected/ fixtures regenerated via 'python -m tools.skillgen
--bless'. --check / --audit-coverage / --schema-singleton /
--monolith-roundtrip / --always-on-roundtrip all green; tests/test_skillgen.py
64/64 pass.
…r export to single quotes

Follow-up to Graphify-Labs#2905 addressing four new Graphify advisory findings on the
post-fix render (review at 12c3b67):

- HIGH (graphify/skills/agents/references/transcribe.md:28) — the
  `export GRAPHIFY_WHISPER_PROMPT="<...>"` pattern left the
  one-sentence domain hint inside double quotes, so a hint containing
  ``, `$(...)`, or `"`, or an LLM-generated hint with shell
  metacharacters, would be evaluated by bash during export. Switching to
  single-quoted assignment plus a separate `export` line keeps the
  prompt literal; the standard `'\\''` escape pattern is documented
  in-line for hints that themselves contain an apostrophe.

- MEDIUM (graphify/skills/claw/references/query.md:171,
  tools/skillgen/expected/graphify__skills__amp__references__query.md:174,
  tools/skillgen/expected/graphify__skills__copilot__references__query.md:171)
  — the prose around the save-result --question/--answer/--nodes block
  only documented the `'\\''` escape for *node labels*, leaving
  ORIGINAL_QUESTION and ANSWER without explicit guidance. A question
  like `What's the difference?` substituted into `'ORIGINAL_QUESTION'`
  produced a bash syntax error (unmatched single quote). Sabotage run
  confirms the old pattern fails with `unexpected EOF while looking
  for matching '\''`; the new pattern with `'\\''` escape parses
  cleanly. The escape guidance now explicitly names ORIGINAL_QUESTION,
  ANSWER, and node labels as the three substituted values that need it.

Source-of-truth fragments edited
(`tools/skillgen/fragments/references/shared/transcribe.md`,
`tools/skillgen/fragments/references/query/default.md`), then all 14
platform renders + matching `expected/` fixtures regenerated.

Verification:
- `python -m tools.skillgen --check` → OK, 134 artifacts match
- `python -m tools.skillgen --audit-coverage` → OK
- `python -m tools.skillgen --schema-singleton` → OK
- `python -m tools.skillgen --monolith-roundtrip` → OK
- `python -m tools.skillgen --always-on-roundtrip` → OK
- `python -m pytest tests/test_skillgen.py` → 64/64 pass
- Sabotage run: old save-result pattern with apostrophe-containing
  question → bash syntax error; new pattern → parses cleanly.
  Old double-quoted Whisper export with `$(touch ...)` injection →
  executes the command (file created); new single-quoted export → keeps
  the value literal (no file created).
@santhiprakash
santhiprakash force-pushed the fix/quote-graphify-python-in-references branch from 97bc499 to 897a76c Compare August 25, 2026 05:30

@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

Hardens all agent-skill reference snippets against shell injection by quoting "$(cat graphify-out/.graphify_python)" and passing user-supplied values (URLs, questions, answers, node labels, whisper prompts) as separate single-quoted sys.argv/CLI arguments instead of interpolating them into evaluated Python source. Updates the accompanying instructions to explain the injection-safe substitution and the '\'' escaping rule for literal single quotes, and regenerates the matching tools_skillgen expected fixtures across every agent variant (claude, codex, copilot, droid, kilo, kiro, opencode, pi, trae, vscode, windows, amp).

Worth a look

  • User query placeholders remain inside double-quoted python -c scriptsgraphify/skills/opencode/references/query.md:77 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Inline query fallback embeds user query in shell-evaluated Python sourcetools/skillgen/expected/graphify__skills__claw__references__query.md:77 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

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

Health — grade A; no new coupling hotspots.

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

…f embedding in python -c

Addresses the latest Graphify review findings on PR Graphify-Labs#2905:
- User query placeholders no longer live inside double-quoted python -c scripts.
- Inline query/path/explain fallbacks pass QUESTION, NODE_A/B, and NODE_NAME as
  single-quoted shell arguments and read them via sys.argv inside the script.
- CLI examples now use single quotes for user-supplied values.
- Guidance explains the '\'' escape for literal single quotes in every value.

Regenerated all 14 platform references and the tools/skillgen expected fixtures.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@santhiprakash

Copy link
Copy Markdown
Contributor Author

Addressed the two HIGH findings from review at head 897a76c:

  • graphify/skills/opencode/references/query.md and tools/skillgen/expected/graphify__skills__claw__references__query.md no longer embed user query values inside a python -c source string.
  • Query, path, and explain inline fallbacks now pass user values (QUESTION, MODE, BUDGET, NODE_A, NODE_B, NODE_NAME) as single-quoted shell arguments and read them via sys.argv.
  • graphify query / graphify path / graphify explain CLI examples also use single quotes for user-supplied values.
  • Guidance documents the '\\'' escape for literal single quotes in every substituted value.

Verification:

  • python -m tools.skillgen regenerated 134 artifacts
  • python -m tools.skillgen --check OK
  • python -m pytest tests/test_skillgen.py 64/64 passed
  • graphify update . completed
  • Rebased onto upstream/v8 and pushed head 764cd29; CI checks are running.

@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 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

Hardens all the graphify skill reference snippets against shell injection by passing user-supplied values (URLs, questions, node labels, paths) as single-quoted sys.argv arguments instead of interpolating them directly into the evaluated Python source, and documents the '\'' escape for literal single quotes. Also quotes "$(cat graphify-out/.graphify_python)" so interpreter paths with spaces resolve correctly, and switches the CLI examples to single-quoted arguments. Regenerates the corresponding tools/skillgen expected fixtures and shared fragments to match.

Worth a look

  • int(sys.argv[3]) raises ValueError if BUDGET placeholder left unreplaced or omittedgraphify/skills/agents/references/query.md:140 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

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

Health — grade A; no new coupling hotspots.

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

@santhiprakash

Copy link
Copy Markdown
Contributor Author

Addressed the int(sys.argv[3]) ValueError in e531703: token_budget now defaults to 2000 when the third argument is missing or non-integer (e.g. the literal BUDGET placeholder). All 14 platform query references and tools/skillgen/expected/ fixtures were regenerated; python3 -m tools.skillgen --check, pytest tests/test_skillgen.py, and the CI matrix are green on the new head.

@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 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

Hardens the generated graphify skill reference docs against shell injection by quoting "$(cat graphify-out/.graphify_python)" and passing all user-supplied values (URLs, questions, node labels, budgets, modes) as single-quoted sys.argv arguments instead of interpolating them into the evaluated Python source. Updates the inline snippets to read those values via sys.argv with a safe token_budget fallback of 2000, and documents the '\'' escape for literal single quotes. Applies the same treatment across every agent variant (claude, codex, copilot, droid, kiro, trae, opencode, windows, etc.) and their expected-output fixtures under tools/skillgen.

Worth a look

  • Quoting .graphify_python narrows it from command line to single executablegraphify/skills/codex/references/update.md:10 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

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

Health — grade A; no new coupling hotspots.

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

@santhiprakash

Copy link
Copy Markdown
Contributor Author

Re the codex/references/update.md:10 advisory (quoting narrows .graphify_python from command line to single executable): the file is a single interpreter path by contract, not a command line. The bootstrap fragments that create it write exactly one path — tools/skillgen/fragments/shell/posix.md:32 writes sys.executable, powershell.md:54 writes $GRAPHIFY_PYTHON — and the standing instruction in both fragments is to substitute it for a bare python3. Quoting "$(cat graphify-out/.graphify_python)" preserves that documented single-path usage byte-for-byte; it only removes unquoted word-splitting/globbing on the value. Nothing in the skills ever documents args inside that file, so there is no documented behavior being narrowed.

@santhiprakash

Copy link
Copy Markdown
Contributor Author

@Graphify-Labs — this finding is a false positive for the documented .graphify_python file format.

  • graphify-out/.graphify_python is written by graphify install / graphify hook install and contains a single absolute interpreter path (not a command line). This is the same source the hooks probe uses in graphify/hooks.py.
  • The graphify hooks themselves quote the value as "$_FROM_FILE" when invoking it, so quoting "$(cat graphify-out/.graphify_python)" here matches the project's own interpreter-guard pattern.
  • The change is intentional: the original bug (Windows: references/ read .graphify_python unquoted - any username with a space breaks query and update (0.9.46) #2856) was bash word-splitting the interpreter path when it contains spaces (e.g. C:\Users\Jane Doe\... on Windows). Removing the quotes would reintroduce that failure.
  • The PowerShell equivalent in skill-windows.md (& (Get-Content graphify-out\.graphify_python) -) likewise treats the file content as a single command, so the two variants stay consistent.

python3 -m tools.skillgen --check and tests/test_skillgen.py are both green on the current head (e531703). Unless the file format changes to allow arguments, the quoted command substitution is the correct, space-safe invocation.

…hs keep space support

The previous fix quoted $(cat graphify-out/.graphify_python) so paths with
spaces worked, but the Graphify reviewer noted that quoting the whole
substitution narrows it to a single executable and prevents passing flags.

Switch every reference fragment to read the file into a bash array with
readarray -t GFY_PYTHON and then invoke "${GFY_PYTHON[@]} ...". A single
line (the default written by Step 1) still resolves as one element, so paths
with spaces continue to work. Optional interpreter flags can be placed on
subsequent lines, restoring the command-line flexibility without re-opening
the word-splitting bug.

Regenerated all platform reference artifacts and expected/ snapshots.

Verification:
- python3 -m tools.skillgen --check
- python3 -m tools.skillgen --audit-coverage --schema-singleton --monolith-roundtrip --always-on-roundtrip
- python3 -m pytest tests/test_skillgen.py -q

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@santhiprakash

santhiprakash commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 6e569d9 to address the latest Graphify advisory on .graphify_python narrowing.

Instead of quoting the whole $(cat graphify-out/.graphify_python) substitution, each reference now reads graphify-out/.graphify_python into a bash array with readarray -t GFY_PYTHON and invokes "${GFY_PYTHON[@]}". A single-line file (the default written by Step 1) still resolves as one element, so paths with spaces keep working, while optional interpreter flags can be placed on subsequent lines if needed. Regenerated all platform variants and expected/ snapshots; CI is green.

@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 5 advisory finding(s) below merit a look before merge.


Graphify review — findings

Hardens all generated Graphify skill reference snippets against shell injection by replacing $(cat graphify-out/.graphify_python) with a readarray/"${GFY_PYTHON[@]}" invocation and moving every user-supplied value (URLs, questions, node labels, budgets, paths) out of the evaluated Python source into single-quoted sys.argv arguments. Updates the accompanying docs to instruct single-quoting each substitution and escaping literal single quotes as '\'', and switches CLI examples to single-quoted arguments. Applies the same rewrite across the query, path, explain, exports, transcribe, update, and add-watch references for every agent variant and their skillgen expected-output fixtures.

Worth a look

  • argv placeholders not single-quoted despite instructions claiming injection safetygraphify/skills/amp/references/add-watch.md:29 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • .graphify_python multi-word commands are no longer executablegraphify/skills/agents/references/add-watch.md:10 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • transcribe snippet has the same broken multi-word interpreter handlinggraphify/skills/agents/references/transcribe.md:32 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • .graphify_python no longer supports single-line commands with argumentsgraphify/skills/agents/references/update.md:8 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • URL/AUTHOR/CONTRIBUTOR placeholders still interpolated into shell single-quotes rather than passed safelygraphify/skills/amp/references/add-watch.md:29 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

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

Health — grade A; no new coupling hotspots.

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

@santhiprakash

Copy link
Copy Markdown
Contributor Author

All 5 advisories on 6e569d9 re-check as false positives against the repo's own writer:

  • Multi-word interpreter (×3 — agents/references/add-watch.md:10, transcribe.md:32, update.md:8): .graphify_python is only ever written by open('graphify-out/.graphify_python','w').write(sys.executable) (skill bootstrap at skill.md:98/673 and per-variant equivalents) — a single absolute interpreter path, never a command line with arguments. Multi-word commands were never a supported format, so nothing regressed. For this contract readarray -t GFY_PYTHON < .graphify_python + "${GFY_PYTHON[@]}" -c is semantically identical to the old $(cat ...) -c, and additionally keeps space-containing paths (Windows C:\Program Files\..., cf. post-commit hook's interpreter allowlist rejects backslashes → silent failure on Windows paths (despite the "covers Windows paths" comment) #2126 allowlist test) intact — which the old word-splitting $(cat ...) broke. That is the point of this commit.
  • "argv placeholders not single-quoted" (amp/references/add-watch.md:29, escalate/high): line 29 is exactly " 'URL' 'AUTHOR' 'CONTRIBUTOR' — single-quoted placeholders, with the '\'' literal-quote escape rule documented one line below.
  • "placeholders interpolated into shell single-quotes": single-quoted argv is the safe channel here — values reach Python via sys.argv, never enter the evaluated Python source, and shell metacharacters are inert inside single quotes.

Gate verdict for this head is PASS with advisories explicitly non-blocking; no change needed.

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.

Windows: references/ read .graphify_python unquoted - any username with a space breaks query and update (0.9.46)

1 participant