Skip to content

graphify install rewrites the whole of CLAUDE.md to CRLF on Windows, and the re-install guard is a bare "graphify" substring match (_CLAUDE_MD_MARKER is dead code) #3668

Description

@kevinishii-spec

Observed on a real graphify install (0.9.64, Windows 11, Python 3.12, installed via uv tool install graphifyy). The install itself worked — skill and references copied correctly. Two problems in _register_always_on_block (graphify/install.py:754-774), both affecting the claude / windows / codebuddy paths only.

1. The whole of CLAUDE.md is rewritten to CRLF on Windows

target.write_text(content.rstrip() + registration, encoding="utf-8")

Path.write_text opens in text mode, so on Windows every \n becomes \r\n — including the user's pre-existing content, which is read back with read_text and rewritten wholesale. Measured on my ~/.claude/CLAUDE.md:

bytes CRLF bare LF
before install 3,365 0 82
after install 3,678 85 0

Three lines were added; 85 lines changed. For anyone keeping ~/.claude/CLAUDE.md in a dotfiles repo — or syncing it between a Windows box and a Linux one, which is a common Claude Code setup — a one-line registration lands as a whole-file diff. Same class as #2655 (export sized for NAME_MAX, ignoring Windows MAX_PATH).

Fix: target.write_bytes((content.rstrip() + registration).encode("utf-8")), or pass newline="" via an explicit open(). Worth auditing the other write_text call sites on this path — gemini_install writes GEMINI.md the same way.

2. The idempotency guard is a bare substring match, and _CLAUDE_MD_MARKER is dead code on this path

_CLAUDE_MD_MARKER = "## graphify"        # install.py:745
...
if "graphify" in content:                 # install.py:765
    print(f"{prefix}already registered (no change)")

Three things don't line up:

  • The guard tests for the bare word "graphify" anywhere in the file, not for the marker.
  • _CLAUDE_MD_MARKER is never referenced on this path. _replace_or_append_section — which does use a marker, correctly — is only wired to gemini_install.
  • What actually gets written by _skill_registration is # graphify (H1), so even if the marker were used it wouldn't match ## graphify (H2).

Failure modes:

  1. Silent non-registration. A user whose CLAUDE.md mentions graphify for any other reason — a note to self, a project instruction, a link to this repo — gets already registered (no change) and no registration block, with no way to tell the difference from a real skip.
  2. No refresh path. If the block is edited, truncated, or the skill path changes, re-running install cannot repair it — the word is still present, so it no-ops. _replace_or_append_section exists precisely for this and is right there.
  3. Heading level is inconsistent with the other three *_MD_MARKER constants, which all specify ## graphify.

Fix: use the existing _replace_or_append_section(content, _CLAUDE_MD_MARKER, ...) helper here as gemini_install already does, and make _skill_registration emit ## graphify so the written heading and the marker agree.

3. Cosmetic: no blank line before the heading

content.rstrip() + registration where registration opens with a single "\n# graphify\n" leaves the heading flush against the user's last paragraph:

or two things that actually block on me get lost in progress narration.
# graphify

Renders fine under CommonMark, but reads as glued to the preceding section in an editor. rstrip() + "\n\n" would settle it.

Happy to send a PR — all three are a handful of lines and item 2 is mostly deleting code in favour of the helper you already have. Equally happy to leave it if you'd rather do it yourself.

Reproduced on graphifyy 0.9.64, Windows 11, uv tool install; line references against site-packages/graphify/install.py from that build. AI-assisted review, all figures measured on the actual install.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions