Skip to content

Windows Codex desktop app creates an empty .git folder, then spawns git process repetitively #29492

Open

Description

@MinetaS

What version of the Codex App are you using (From “About Codex” dialog)?

Version 26.616.51431 • Released Jun 21, 2026

What subscription do you have?

Pro 5x

What platform is your computer?

Microsoft Windows NT 10.0.22631.0 x64

What issue are you seeing?

When the project is not a Git repository, Codex creates an empty .git folder, then subsequently spawns Git processes with this cmdline:

"C:\Program Files\Git\cmd\git.exe" -c core.hooksPath=NUL -c core.fsmonitor=true rev-parse --show-toplevel
"C:\Program Files\Git\cmd\git.exe" config --null --get core.fsmonitor
(and more)

This list seems to match "Observed Commands" section reported in #29408.

What steps can reproduce the bug?

It's difficult to find out which kinds of prompt exactly reproduce the bug, but at some point Windows sandbox touches .agents, .codex, .git which eventually leads to multiple empty directories.

Sandbox log (timezone is UTC+9):

[2026-06-23 06:42:35.134 codex.exe] START: C:\Users\***\.codex\.sandbox-bin\codex.exe --codex-run-as-fs-helper
[2026-06-22T21:42:35.235850600+00:00] applied deny ACE to protect C:\Users\***\***\.agents
[2026-06-22T21:42:35.236659900+00:00] applied deny ACE to protect C:\Users\***\***\.codex
[2026-06-22T21:42:35.237416+00:00] applied deny ACE to protect C:\Users\***\***\.git

What is the expected behavior?

  1. Codex should not create .agents, .codex, .git empty directories randomly.
  2. Codex should not repeatedly spawn Git processes when .git folder is empty or malformed.

Additional information

I believe this issue is the first that enlightens the connection between an unexpected sandbox behavior and the Git process issue.

Activity

  1. added
    appIssues related to the Codex desktop app
    on Jun 22, 2026
  2. added
    bugSomething isn't working
    windows-osIssues related to Codex on Windows systems
    sandboxIssues related to permissions or sandboxing
    on Jun 22, 2026
  3. MinetaS commented on Jun 23, 2026

    @MinetaS
    Author

    #28631 reported a similar bug but it's about VS Code extension on Linux/WSL.
    This issue is about Windows desktop app, but the underlying cause may be likely identical.

  4. rasael commented on Jun 25, 2026

    @rasael

    I have the same issue, and it is problematic because the parent directory is where the real .git and .codex directories are located. As a result, the generated empty folder must be removed before new threads can correctly see my skills and git status again.

    My current workaround is to delete those folders and reload the skills, but I have dozens of submodules under the parent directory, so this is quite annoying.

  5. GuilhermeCouto commented on Jun 25, 2026

    @GuilhermeCouto

    I have the same issue, my codex creates a .git folder inside of my project folder(1 level below the project folder with original .git) and bugs my IDE

  6. Apen commented on Jun 27, 2026

    @Apen

    Same problem here. My workaround is a PowerShell script that finds empty .git folders and "git init"s them.
    Before that, I had a loooot of Git processes spawning continuously; now, a few at the beginning and after nothing.

  7. privacyguy123 commented on Jun 29, 2026

    @privacyguy123

    Same bug is back in todays build for me - the previous fix was to delete an orphaned .git folder in .codex but there isn't one there anymore.

  8. rasael commented on Jun 29, 2026

    @rasael

    While waiting for a fix, I've taken the workaround script tip from @Apen and vibed a PowerShell script to identify and delete those empty folders. I now run it before any new thread and resumed 'normal' operation with codex.

    The script searches from the root and enumerates all empty .git, .codex, .agents empty folders it finds and then deletes them; really saves me a lot of time.

  9. privacyguy123 commented on Jun 29, 2026

    @privacyguy123

    While waiting for a fix, I've taken the workaround script tip from @Apen and vibed a PowerShell script to identify and delete those empty folders. I now run it before any new thread and resumed 'normal' operation with codex.

    The script searches from the root and enumerates all empty .git, .codex, .agents empty folders it finds and then deletes them; really saves me a lot of time.

    Where is this script?

    Realistically where would I even have empty .git folders created "by mistake"?

  10. rasael commented on Jun 29, 2026

    @rasael

    Where is this script?

    I reccomend you vibe code with codex yourself, tailored for your specific case.

    Here is my version, tailored for a multi module project:

    <#
    .SYNOPSIS
    Finds and permanently deletes empty .agents, .codex, and .git folders.
    
    .DESCRIPTION
    Run this script from the repo root. The repo root is treated as the folder that
    contains this script. The scan walks only through folders whose names do not
    start with a dot, skips src and target folders, and it marks empty .agents,
    .codex, and .git child folders for deletion. The candidate folder names and
    excluded traversal folder names are configurable through the $CandidateNames and
    $ExcludedTraversalNames lists near the top of the script.
    
    .PARAMETER ForceDelete
    Deletes the marked empty folders without prompting for confirmation.
    #>
    [CmdletBinding()]
    param(
        [Alias('Force')]
        [switch] $ForceDelete
    )
    
    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'
    
    # Treat the folder containing this script as the repo root, no matter where the
    # caller's current PowerShell location happens to be.
    $RepoRoot = (Resolve-Path -LiteralPath $PSScriptRoot).ProviderPath
    
    # Metadata folder names that should be deleted when they are empty.
    $CandidateNames = @('.agents', '.codex', '.git')
    
    # Directory names that should not be traversed while searching.
    $ExcludedTraversalNames = @('src', 'target')
    
    # Print a heartbeat every N scanned folders so long runs look alive.
    $ProgressInterval = 250
    
    function Test-EmptyDirectory {
        param(
            [Parameter(Mandatory = $true)]
            [string] $Path
        )
    
        if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
            return $false
        }
    
        try {
            # Reading one child is enough to prove the directory is not empty.
            $firstItem = Get-ChildItem -LiteralPath $Path -Force -ErrorAction Stop | Select-Object -First 1
            return $null -eq $firstItem
        }
        catch {
            Write-Warning "Could not inspect folder: $Path"
            return $false
        }
    }
    
    function Get-ScannableDirectory {
        param(
            [Parameter(Mandatory = $true)]
            [string] $Root
        )
    
        # Use an explicit stack so traversal can stream paths as they are found.
        $stack = [System.Collections.Generic.Stack[string]]::new()
        $stack.Push($Root)
    
        while ($stack.Count -gt 0) {
            $current = $stack.Pop()
            $currentItem = Get-Item -LiteralPath $current -Force -ErrorAction Stop
    
            if (($currentItem.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) {
                continue
            }
    
            # Emit the current folder before discovering its children.
            $current
    
            $children = Get-ChildItem -LiteralPath $current -Directory -Force -ErrorAction SilentlyContinue |
                Where-Object {
                    # Do not descend into dot folders, configured exclusions, or links.
                    $_.Name -notlike '.*' -and
                    $_.Name -notin $ExcludedTraversalNames -and
                    (($_.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -eq 0)
                } |
                Sort-Object -Property FullName -Descending
    
            foreach ($child in $children) {
                $stack.Push($child.FullName)
            }
        }
    }
    
    # Track marked folders separately from already-seen paths so duplicate discovery
    # cannot print or delete the same path twice.
    $markedFolders = [System.Collections.Generic.List[string]]::new()
    $seenFolders = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
    $scannedFolderCount = 0
    
    Write-Host "Scanning under:"
    Write-Host "  $RepoRoot"
    Write-Host "Empty metadata folders will be printed as they are found."
    Write-Host ''
    
    # Stream the traversal so progress and found-folder output appears immediately.
    Get-ScannableDirectory -Root $RepoRoot | ForEach-Object {
        $folder = $_
        $scannedFolderCount++
    
        if (($scannedFolderCount % $ProgressInterval) -eq 0) {
            Write-Host "Scanned $scannedFolderCount folders..."
        }
    
        foreach ($candidateName in $CandidateNames) {
            $candidatePath = Join-Path -Path $folder -ChildPath $candidateName
    
            # Mark only configured metadata folders that currently exist and are empty.
            if (Test-EmptyDirectory -Path $candidatePath) {
                $resolvedPath = (Resolve-Path -LiteralPath $candidatePath).ProviderPath
    
                if ($seenFolders.Add($resolvedPath)) {
                    Write-Host "Found: $resolvedPath"
                    $markedFolders.Add($resolvedPath)
                }
            }
        }
    }
    
    Write-Host ''
    Write-Host "Scan complete. Scanned $scannedFolderCount folder(s)."
    
    # Keep the final confirmation list stable and deterministic.
    $markedFolders = @($markedFolders | Sort-Object -Unique)
    
    if ($markedFolders.Count -eq 0) {
        Write-Host "No empty .agents, .codex, or .git folders found under:"
        Write-Host "  $RepoRoot"
        exit 0
    }
    
    Write-Host "The following empty folders are marked for permanent deletion:"
    foreach ($folder in $markedFolders) {
        Write-Host "  $folder"
    }
    
    # The default path requires a typed confirmation; -ForceDelete skips only this
    # prompt, not the final emptiness check before deletion.
    if ($ForceDelete) {
        Write-Host ''
        Write-Host 'Force delete option supplied. Deleting without confirmation.'
    }
    else {
        Write-Host ''
        $confirmation = Read-Host 'Type DELETE to permanently remove these folders'
    
        if ($confirmation -cne 'DELETE') {
            Write-Host 'Cancelled. No folders were deleted.'
            exit 0
        }
    }
    
    $deletedCount = 0
    $skippedCount = 0
    
    foreach ($folder in $markedFolders) {
        # Re-check just before deleting so changed folders are skipped safely.
        if (Test-EmptyDirectory -Path $folder) {
            try {
                Remove-Item -LiteralPath $folder -Force -ErrorAction Stop
                Write-Host "Deleted: $folder"
                $deletedCount++
            }
            catch {
                Write-Warning "Could not delete folder: $folder"
                $skippedCount++
            }
        }
        else {
            Write-Warning "Skipped because it is no longer empty or no longer exists: $folder"
            $skippedCount++
        }
    }
    
    Write-Host ''
    Write-Host "Done. Deleted $deletedCount folder(s). Skipped $skippedCount folder(s)." 

    Realistically where would I even have empty .git folders created "by mistake"?

    In my case codex creates those 2-3 empty folders for every module I open in codex

    Scan complete. Scanned 2635 folder(s).
    The following empty folders are marked for permanent deletion:
      R:\eda\cted\commons-desktop\commons-desktop-api\.agents
      R:\eda\cted\commons-desktop\commons-desktop-api\.codex
      R:\eda\cted\commons-desktop\commons-desktop-api\.git
      R:\eda\cted\commons-desktop\commons-desktop-graph\.agents
      R:\eda\cted\commons-desktop\commons-desktop-graph\.git
      R:\eda\cted\game\game-ui\.agents
      R:\eda\cted\game\game-ui\.codex
      R:\eda\cted\game\game-ui\.git
      R:\eda\cted\php-dashboard\.agents
      R:\eda\cted\php-dashboard\.git
    

    note that the main .git file would be at R:\eda\cted\.git, and so is the main .codex folder.

  11. privacyguy123 commented on Jun 30, 2026

    @privacyguy123

    You must admit this is an absolutely gross fix - why are orphaned .git folders being created in the first place?

  12. MinetaS commented on Jun 30, 2026

    @MinetaS
    Author

    I ended up with creating empty .agents, .codex, .git files (not folders) with proper ACLs to mitigate this for now.

    It's kind of unfortunate that this has not been noticed by OpenAI teams yet. I'm seeing several duplicate issues which means there are quite amount of users impacted by this specific bug in sense of the performance degradation. Hopefully this will be addressed soon.

  13. rolandorojas commented on Jul 5, 2026

    @rolandorojas

    It looks like this behavior also triggers Windows Defender to continuously scan the git-hammered folder. In my case, this doubles or triples the performance hit caused by the bug.

    It's extremely noticeable. I can hear my fans spinning and a second after closing Codex, everything quiets down.

  14. amerina commented on Jul 9, 2026

    @amerina

    this problem fuck me every day😭,can god resolve this,because company us tfs still

  15. suiyuebaobao commented on Jul 22, 2026

    @suiyuebaobao

    The empty .git discovery loop and repeated Git spawning here are the same class of Git-backed refresh workload I reproduced.

    I published a single-file Windows launcher for the original Microsoft Store/MSIX Codex app:

    It starts Codex with a process-scoped GIT_DIR=NUL. On my machine, the stable trace changed from 247 new git.exe and 137 new taskkill.exe processes per 10 seconds to 0 and 0 over 15 seconds; WMI Provider Host fell from about 6.6% to 0.9%.

    Usage: fully exit Codex from the Windows system tray, then run the script.

    This is an unofficial workaround, not an upstream fix. It deliberately disables or limits Review, Changes, branch detection, commit, and other Git-backed Codex features. It does not patch Codex, modify repositories or Git configuration, write system environment variables, require elevation, terminate processes, or remove chat history. Launching Codex normally restores Git integration.

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

    appIssues related to the Codex desktop appbugSomething isn't workingsandboxIssues related to permissions or sandboxingwindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions