Summary
The bundled CodeGraph SessionStart helper writes .git/info/exclude whenever a .git path exists, even when that path is an empty or otherwise invalid repository marker. On Windows, Codex can leave such invalid .git directories behind; CodeGraph then mutates them into a more persistent partial Git structure, which combines badly with Codex Desktop's repeated Git discovery.
Environment
- LazyCodex installed:
4.16.2
- Latest LazyCodex source checked:
bb8764ca1754148ca56478d433c42b91c550e0f4 (main)
- Codex Desktop:
26.707.3748.0
- Codex CLI:
0.144.1
- OS: Windows 11 Pro for Workstations, build
26200, x64
- Relevant config: OMO CodeGraph MCP and SessionStart hook enabled
Repository Decision
Reproduction
- Create a normal non-Git workspace.
- Create an empty
.git directory in it, matching the invalid marker produced by the Windows sandbox report.
- Run the LazyCodex CodeGraph SessionStart bootstrap for that workspace.
- Inspect
.git/info/exclude and run git -C <workspace> rev-parse --is-inside-work-tree.
Minimal state before the hook:
workspace/
.git/ # empty, not a repository
Observed state after the hook:
workspace/
.git/
info/
exclude # contains .codegraph
git rev-parse --is-inside-work-tree still fails because the workspace is not a repository.
Expected Behavior
CodeGraph must leave an invalid .git path untouched. It should write an exclude entry only after Git confirms that the workspace is a valid worktree and resolves the correct per-worktree exclude path.
Actual Behavior
ensureCodegraphGitignored() treats existence as validity:
const gitDir = join(workspace, ".git");
if (!existsSync(gitDir)) return false;
const excludePath = join(gitDir, "info", "exclude");
mkdirSync(join(gitDir, "info"), { recursive: true });
appendFileSync(excludePath, ".codegraph\n");
On the affected machine, D:\TTS\.git was created at 10:17:14 as an invalid marker. At 17:27:30, after CodeGraph startup, its only content became .git/info/exclude with the 11-byte value .codegraph\n. The top-level .git creation predates the CodeGraph write, so CodeGraph did not create the marker but did mutate and preserve the invalid structure.
Evidence
Root Cause
Repository validity is reduced to existsSync(<workspace>/.git). This does not distinguish a valid repository from an empty sandbox-created directory, and it does not handle linked worktrees where .git is a file. The helper then creates repository-internal paths before Git has validated or resolved them.
Proposed Fix
- Ask Git to validate and resolve the path, for example with a bounded
git -C <workspace> rev-parse --git-path info/exclude after confirming --is-inside-work-tree.
- Do not call
mkdirSync or appendFileSync when validation fails.
- Use the Git-resolved exclude path so linked worktrees are handled correctly.
- Add regression tests for an empty
.git directory, a normal repository, and a linked worktree whose .git is a file.
Verification Plan
- Given an empty
.git, the hook returns a skipped/not-repository result and leaves the filesystem unchanged.
- Given a valid repository,
.codegraph is added once to the Git-resolved exclude file.
- Given a linked worktree, the exclude entry is written to the correct common/worktree Git path without replacing the
.git file.
- Re-running SessionStart remains idempotent.
This issue or PR was generated by LazyCodex.
Tag: lazycodex-generated
Summary
The bundled CodeGraph SessionStart helper writes
.git/info/excludewhenever a.gitpath exists, even when that path is an empty or otherwise invalid repository marker. On Windows, Codex can leave such invalid.gitdirectories behind; CodeGraph then mutates them into a more persistent partial Git structure, which combines badly with Codex Desktop's repeated Git discovery.Environment
4.16.2bb8764ca1754148ca56478d433c42b91c550e0f4(main)26.707.3748.00.144.126200, x64Repository Decision
code-yeongyu/lazycodexplugins/omo/components/codegraph/dist/cli.js, lines 307-325, containsensureCodegraphGitignored(). It checks onlyexistsSync(workspace/.git), recursively creates.git/info, and appends.codegraphtoexclude..gitmarker. CodeGraph should still treat that as invalid input and avoid mutating it.Reproduction
.gitdirectory in it, matching the invalid marker produced by the Windows sandbox report..git/info/excludeand rungit -C <workspace> rev-parse --is-inside-work-tree.Minimal state before the hook:
Observed state after the hook:
git rev-parse --is-inside-work-treestill fails because the workspace is not a repository.Expected Behavior
CodeGraph must leave an invalid
.gitpath untouched. It should write an exclude entry only after Git confirms that the workspace is a valid worktree and resolves the correct per-worktree exclude path.Actual Behavior
ensureCodegraphGitignored()treats existence as validity:On the affected machine,
D:\TTS\.gitwas created at10:17:14as an invalid marker. At17:27:30, after CodeGraph startup, its only content became.git/info/excludewith the 11-byte value.codegraph\n. The top-level.gitcreation predates the CodeGraph write, so CodeGraph did not create the marker but did mutate and preserve the invalid structure.Evidence
plugins/omo/components/codegraph/dist/cli.js:307-325atbb8764ca1754148ca56478d433c42b91c550e0f4.D:\TTS\.git; only.git/info/exclude; exact bytes2e 63 6f 64 65 67 72 61 70 68 0a(.codegraph\n).git -C D:\TTS rev-parse --is-inside-work-treefails.Root Cause
Repository validity is reduced to
existsSync(<workspace>/.git). This does not distinguish a valid repository from an empty sandbox-created directory, and it does not handle linked worktrees where.gitis a file. The helper then creates repository-internal paths before Git has validated or resolved them.Proposed Fix
git -C <workspace> rev-parse --git-path info/excludeafter confirming--is-inside-work-tree.mkdirSyncorappendFileSyncwhen validation fails..gitdirectory, a normal repository, and a linked worktree whose.gitis a file.Verification Plan
.git, the hook returns a skipped/not-repository result and leaves the filesystem unchanged..codegraphis added once to the Git-resolved exclude file..gitfile.This issue or PR was generated by LazyCodex.
Tag: lazycodex-generated