facebook pixel
Turn Your Repo Into One File for Smarter AI Reviews — Try This Now!
13 min readBy Indie4Tune Team

Turn Your Repo Into One File for Smarter AI Reviews — Try This Now!

One file to rule the repo, and why that changes everything

Most reviews fail where context gets sliced thin. A pull request shows a tidy diff, meanwhile the real story hides across services, scripts, and tests. Reviewers hop between tabs, miss cross‑module assumptions, then spend a sprint fixing what slipped through. A simple habit changes that, create a single, prompt‑friendly text file of the whole repository, let your AI assistant read it end to end, then ask for an honest critique.

GitHub Copilot’s documented strengths include refactoring, maintainability improvements, unit test generation, and diagramming when you give it enough context, and consolidation lifts the ceiling on all of those outcomes (Copilot Chat Cookbook, Copilot docs). GitHub also rolled out richer file interactions, previews, and attachments on github.com, which makes long reviews more practical in the browser (changelog).

Quick links: What this script does in one run · Generate a single-file repo digest behind the firewall · Usage, prompts, and review flow · Keep IP inside the perimeter · Appendix A, full PowerShell script · Further Reading


What this script does in one run

Use the PowerShell script in this article to produce a single text file that includes the directory tree, filtered code contents, dependency info, and a clean summary. Keep it inside your perimeter, share it with Copilot or Claude, and request deep analysis without juggling files.

For public GitHub repos, tools like Gitingest and Repomix do similar packaging automatically. They excel when privacy is not a concern and when token budgeting matters (Gitingest site, Repomix site).

What the output looks like, a small slice for flavor.

=== Project Information ===
Generated on: 2025-10-29

=== Project Structure ===
src/controllers/authController.ts
src/services/userService.ts
tests/auth.spec.ts

=== Code Files Content ===
----- src/controllers/authController.ts -----
export async function login(req, res) { ... }

=== Dependency Information ===
Dependencies:
express: ^4.19.2
jsonwebtoken: ^9.0.2

Dev Dependencies:
vitest: ^2.0.0

=== Summary ===
Project directory: C:\Repos\MyProject
Output file: C:\Reports\MyProject-info.txt

With one file, AI stops guessing. It sees naming patterns, repeated utilities, and tests that never touch edge cases. GitHub’s Copilot Chat improvements on github.com, richer attachments and file previews, make it easier to inspect AI feedback without losing your place (changelog).


Why the single‑file digest matters

Holistic reviews, not line diffs. Models track design decisions across modules, spot duplicated logic, and call out brittle interfaces. Copilot’s cookbook covers performance refactoring, readability, test generation, and diagram creation, all of which improve when a digest provides complete context (Cookbook, Create diagrams).

Design alignment you can verify. Ask for swimlanes that mirror actual code paths, then compare the diagram with your design docs in the same file. The assistant points to mismatches and proposes adjustments. Copilot’s prompt recipes make this natural (Cookbook).

Fewer “we fixed it, right” moments. Code comments claim a fix, tests tell a different story. A single digest lets the model check both and suggest the missing assertions. For public repos, Gitingest and Repomix add useful stats, token counts, and formatting that help you plan what to include within model limits (Gitingest README, Repomix features).


Tools that help GitHub users

When a repo is open source, convenience wins.

  • Gitingest. Replace “hub” with “ingest” in a GitHub URL, or run the CLI, and you get a prompt‑friendly text digest with structure, contents, and token counts. It respects .gitignore, supports private repos via PAT, and ships a browser extension for quick use (site, repo, PyPI).
  • Repomix. Pack the entire codebase into one AI‑friendly file, choose Markdown or XML, compress code with Tree‑sitter to reduce tokens, remove comments, count tokens, and run Secretlint to avoid leaking credentials (site, repo).

These tools shine for public repos and onboarding, they offer instant extracts and transparent budgets. For enterprise IP, a local script keeps the same benefits while staying on your side of the firewall. GitHub’s Copilot docs outline enterprise controls for content exclusion and network settings, which pair well with a local packaging approach (content exclusion concept, how‑to).


Generate a single‑file repo digest behind the firewall

Core excerpt, the essentials from the full PowerShell script, trimmed for readability. This version initializes the output, writes structure, copies filtered code files, and captures dependency info, all on local disk.

# Generate-ProjectInfo.ps1 (core excerpt)
[CmdletBinding()]
param(
    [Parameter(Mandatory=$false)]
    [string]$Root = (Get-Location).Path,

    [Parameter(Mandatory=$false)]
    [string]$OutputFile = "project_info.txt"
)

# Directories to exclude
$ExcludeDirs = @(
    'node_modules','build','dist','.git','.expo','.venv',
    '.next','.output','.turbo','.cache','coverage',
    'target','gradle','.gradle','vendor','Pods',
    '.pytest_cache','.mypy_cache','.ruff_cache'
)

# Include common code extensions
$CodeExtensions = @('js','jsx','ts','tsx','py','rb','java','cpp','c','h','sh')

function Initialize-OutputFile {
    param([string]$Path)
    $dir = Split-Path -Path $Path -Parent
    if ($dir -and -not (Test-Path -LiteralPath $dir)) {
        New-Item -ItemType Directory -Path $dir -Force | Out-Null
    }
    Set-Content -Path $Path -Value "=== Project Information ==="
    Add-Content -Path $Path -Value ("Generated on: {0}" -f (Get-Date))
    Add-Content -Path $Path -Value ""
}

function Write-Section { param([string]$Title) Add-Content -Path $OutputFile -Value ("=== {0} ===" -f $Title) }
function Write-Line { param([string]$Text = "") Add-Content -Path $OutputFile -Value $Text }

function Is-UnderExcludedDir {
    param([string]$FullName,[string]$RootPath)
    $relative = $FullName.Substring($RootPath.Length).TrimStart('','/')
    if ([string]::IsNullOrWhiteSpace($relative)) { return $false }
    $segments = $relative -split '[\/]' | Where-Object { $_ -ne "" }
    foreach ($seg in $segments) { if ($ExcludeDirs -contains $seg) { return $true } }
    return $false
}

function Get-ProjectItems {
    param([string]$RootPath)
    Get-ChildItem -LiteralPath $RootPath -Recurse -Force -ErrorAction SilentlyContinue |
        Where-Object {
            if (Is-UnderExcludedDir -FullName $_.FullName -RootPath $RootPath) { return $false }
            return $true
        }
}

function Get-ProjectStructure {
    param([string]$RootPath)
    Write-Line "(tree-like listing with exclusions)"
    $items = Get-ProjectItems -RootPath $RootPath
    $dirs  = $items | Where-Object { $_.PSIsContainer }
    $files = $items | Where-Object { -not $_.PSIsContainer }

    foreach ($dir in ($dirs | Sort-Object FullName)) {
        $rel = $dir.FullName.Substring($RootPath.Length).TrimStart('','/')
        if ($rel) { Write-Line $rel }
    }
    foreach ($file in ($files | Sort-Object FullName)) {
        $rel = $file.FullName.Substring($RootPath.Length).TrimStart('','/')
        if ($rel) { Write-Line $rel }
    }
}

function Get-CodeFiles {
    param([string]$RootPath)
    $items = Get-ProjectItems -RootPath $RootPath
    $files = $items | Where-Object { -not $_.PSIsContainer }
    $files | Where-Object {
        $ext = $_.Extension.TrimStart('.').ToLowerInvariant()
        $CodeExtensions -contains $ext
    }
}

# Begin
$Root = (Resolve-Path -LiteralPath $Root).Path
Initialize-OutputFile -Path $OutputFile

Write-Section "Project Structure"
Get-ProjectStructure -RootPath $Root
Write-Line

Write-Section "Code Files Content"
$codeFiles = Get-CodeFiles -RootPath $Root
foreach ($file in $codeFiles) {
    $rel = $file.FullName.Substring($Root.Length).TrimStart('\','/')
    Write-Line ("----- {0} -----" -f $rel)
    Get-Content -LiteralPath $file.FullName -ErrorAction SilentlyContinue | Add-Content -Path $OutputFile
    Write-Line
}

Write-Section "Dependency Information"
$packageJsonPath = Join-Path $Root "package.json"
$requirementsPath = Join-Path $Root "requirements.txt"
if (Test-Path -LiteralPath $packageJsonPath) {
    $pkg = Get-Content -LiteralPath $packageJsonPath -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue
    Write-Line "Dependencies:"; ($pkg.dependencies | Get-Member -MemberType NoteProperty | ForEach-Object { Write-Line ("{0}: {1}" -f $_.Name, $pkg.dependencies.($_.Name)) }) ; Write-Line
    Write-Line "Dev Dependencies:"; ($pkg.devDependencies | Get-Member -MemberType NoteProperty | ForEach-Object { Write-Line ("{0}: {1}" -f $_.Name, $pkg.devDependencies.($_.Name)) })
} elseif (Test-Path -LiteralPath $requirementsPath) {
    Write-Line "Python Dependencies (requirements.txt):"
    Get-Content -LiteralPath $requirementsPath | Add-Content -Path $OutputFile
} else {
    Write-Line "No dependency file found."
}

Write-Line
Write-Section "Summary"
Write-Line ("Project directory: {0}" -f $Root)
Write-Line ("Output file: {0}" -f (Resolve-Path -LiteralPath $OutputFile).Path)
Write-Line "Done!"

Why this local approach works for enterprises. You keep IP inside the perimeter, you tailor filters to your stack, and you can route the digest to an approved AI endpoint on your own terms. Copilot’s enterprise documentation covers content exclusion and admin controls (concepts, how‑to).


Usage, prompts, and review flow

Run it, keep the output in a controlled folder.

# From repo root
.\Generate-ProjectInfo.ps1
# Or choose paths
.\Generate-ProjectInfo.ps1 -Root "C:\Repos\MyProject" -OutputFile "C:\Reports\MyProject-info.txt"

Feed it to your AI, then ask for layered analysis.

You are reviewing a complete repository digest. First, list performance hotspots with file and line references, then propose concrete refactorings. Next, surface maintainability issues, naming, duplication, dead code. Finally, verify whether documented fixes in /docs match tests in /tests, report gaps, and suggest test cases.

Ask for a swimlane that matches reality.

Extract the end to end login flow as a swimlane, actors (User, Web App, Auth Service, Database). Use Mermaid. Validate against controllers, services, and data access code in the digest. Point out any missing steps.

Copilot’s cookbook includes patterns for refactoring, generating tests, and creating diagrams. Gitingest and Repomix help with public repos by formatting content for prompt consumption and by counting tokens so you plan the slices you send (Cookbook, Gitingest, Repomix).

Automate reviews carefully. If you use GitHub for CI, explore Claude’s GitHub integration to trigger AI reviews on mention, or to draft PRs from issues. Keep permissions tight, run in draft mode first, and log all actions (Claude Code Action repo, setup guide).


Keep IP inside the perimeter

  • Local only. Run the script on managed endpoints, store outputs in internal artifact repositories, and route analysis through approved services. Copilot enterprise controls help admins enforce what leaves the environment (concepts, how‑to).
  • Audit friendly. Attach the digest to a change ticket, require approvals, and keep immutable logs of AI suggestions and applied diffs. Claude’s GitHub Actions documentation and guides show permission scopes and enterprise setups for Bedrock or Vertex (action docs, cloud providers).
  • Secrets stay out. Even local outputs can include credentials if someone committed them by mistake. Repomix integrates Secretlint to catch sensitive strings. Adopt a preflight secret scan and fail the job if anything appears risky (Repomix features).

Appendix A, full PowerShell script

This is the complete script, ready to drop into your tooling. It generates the project report with structure, code contents, dependency info, and a summary, and it excludes common build and dependency folders by default.

<#
.SYNOPSIS
Generates a project report with structure, code contents, and dependency info.

.DESCRIPTION
Produces a text report containing:
  - Project structure (with directory/file listing)
  - Full contents of code files (filtered by extension)
  - Dependency information from package.json or requirements.txt
  - Summary

By default, excludes common build/dependency/derived directories and hidden files.
Output path is customizable.

.PARAMETER Root
Root directory of the project (defaults to the current directory).

.PARAMETER OutputFile
Path to the output report file (relative or absolute). Default: "project_info.txt" in the current directory.

.EXAMPLE
.\Generate-ProjectInfo.ps1

.EXAMPLE
.\Generate-ProjectInfo.ps1 -OutputFile "reports\project_info.txt"

.EXAMPLE
.\Generate-ProjectInfo.ps1 -Root "C:\Repos\MyProject" -OutputFile "C:\Reports\MyProject-info.txt"
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory=$false)]
    [string]$Root = (Get-Location).Path,

    [Parameter(Mandatory=$false)]
    [string]$OutputFile = "project_info.txt"
)

# ---------------------------
# Configuration
# ---------------------------

# Directories to exclude (names only; apply anywhere in the path)
$ExcludeDirs = @(
    'node_modules','build','dist','.git','.expo','.venv',
    '.next','.output','.turbo','.cache','coverage',
    'target','gradle','.gradle','vendor','Pods',
    '.pytest_cache','.mypy_cache','.ruff_cache'
)

# Exclude hidden files/dirs (dotfiles) via Attributes
$ExcludeHidden = $true

# Code extensions to include
$CodeExtensions = @('js','jsx','ts','tsx','py','rb','java','cpp','c','h','sh')

# ---------------------------
# Helpers
# ---------------------------

function Initialize-OutputFile {
    param([string]$Path)
    $dir = Split-Path -Path $Path -Parent
    if ($dir -and -not (Test-Path -LiteralPath $dir)) {
        New-Item -ItemType Directory -Path $dir -Force | Out-Null
    }
    # Overwrite with header
    Set-Content -Path $Path -Value "=== Project Information ==="
    Add-Content -Path $Path -Value ("Generated on: {0}" -f (Get-Date))
    Add-Content -Path $Path -Value ""
}

function Write-Section {
    param([string]$Title)
    Add-Content -Path $OutputFile -Value ("=== {0} ===" -f $Title)
}

function Write-Line {
    param([string]$Text = "")
    Add-Content -Path $OutputFile -Value $Text
}

function Is-UnderExcludedDir {
    param(
        [string]$FullName,
        [string]$RootPath
    )
    # Compute relative segments and check if any segment matches an excluded dir name
    $relative = $FullName.Substring($RootPath.Length).TrimStart('\','/')
    if ([string]::IsNullOrWhiteSpace($relative)) { return $false }
    $segments = $relative -split '[\/]' | Where-Object { $_ -ne "" }
    foreach ($seg in $segments) {
        if ($ExcludeDirs -contains $seg) { return $true }
    }
    return $false
}

function Get-ProjectItems {
    param([string]$RootPath)

    # Use -Force to see hidden items, but we'll filter them out if $ExcludeHidden
    Get-ChildItem -LiteralPath $RootPath -Recurse -Force -ErrorAction SilentlyContinue |
        Where-Object {
            # Exclude anything within excluded directories
            if (Is-UnderExcludedDir -FullName $_.FullName -RootPath $RootPath) { return $false }

            # Exclude hidden items if requested
            if ($ExcludeHidden -and ($_.Attributes -band [IO.FileAttributes]::Hidden)) { return $false }

            return $true
        }
}

function Get-ProjectStructure {
    param([string]$RootPath)

    Write-Line "(PowerShell tree-like listing with exclusions)"
    $items = Get-ProjectItems -RootPath $RootPath

    $dirs  = $items | Where-Object { $_.PSIsContainer }
    $files = $items | Where-Object { -not $_.PSIsContainer }

    foreach ($dir in ($dirs | Sort-Object FullName)) {
        $rel = $dir.FullName.Substring($RootPath.Length).TrimStart('\','/')
        if (-not [string]::IsNullOrWhiteSpace($rel)) { Write-Line $rel }
    }

    foreach ($file in ($files | Sort-Object FullName)) {
        $rel = $file.FullName.Substring($RootPath.Length).TrimStart('\','/')
        if (-not [string]::IsNullOrWhiteSpace($rel)) { Write-Line $rel }
    }
}

function Get-CodeFiles {
    param([string]$RootPath)

    $items = Get-ProjectItems -RootPath $RootPath
    $files = $items | Where-Object { -not $_.PSIsContainer }

    $files | Where-Object {
        $ext = $_.Extension.TrimStart('.').ToLowerInvariant()
        $CodeExtensions -contains $ext
    }
}

# ---------------------------
# Begin
# ---------------------------

# Normalize Root to full path
$Root = (Resolve-Path -LiteralPath $Root).Path

Initialize-OutputFile -Path $OutputFile

# 1) Project Structure
Write-Section "Project Structure"
Get-ProjectStructure -RootPath $Root
Write-Line
# 2) Code Files Content
Write-Section "Code Files Content"
$codeFiles = Get-CodeFiles -RootPath $Root

foreach ($file in $codeFiles) {
    $rel = $file.FullName.Substring($Root.Length).TrimStart('\','/')
    Write-Line ("----- {0} -----" -f $rel)
    try {
        # Output full contents (no size guardrails per request)
        Get-Content -LiteralPath $file.FullName -ErrorAction Stop | Add-Content -Path $OutputFile
    }
    catch {
        Write-Line ("[Error reading file: {0}]" -f $_.Exception.Message)
    }
    Write-Line
}

# 3) Dependency Information
Write-Section "Dependency Information"

$packageJsonPath = Join-Path $Root "package.json"
$requirementsPath = Join-Path $Root "requirements.txt"

if (Test-Path -LiteralPath $packageJsonPath) {
    try {
        $pkg = Get-Content -LiteralPath $packageJsonPath -Raw | ConvertFrom-Json -ErrorAction Stop

        Write-Line "Dependencies:"
        if ($pkg.PSObject.Properties.Name -contains 'dependencies' -and $pkg.dependencies) {
            $pkg.dependencies.GetEnumerator() | Sort-Object Name | ForEach-Object {
                Write-Line ("{0}: {1}" -f $_.Name, $_.Value)
            }
        } else {
            Write-Line "{}"
        }
        Write-Line

        Write-Line "Dev Dependencies:"
        if ($pkg.PSObject.Properties.Name -contains 'devDependencies' -and $pkg.devDependencies) {
            $pkg.devDependencies.GetEnumerator() | Sort-Object Name | ForEach-Object {
                Write-Line ("{0}: {1}" -f $_.Name, $_.Value)
            }
        } else {
            Write-Line "{}"
        }
    }
    catch {
        Write-Line "(Error parsing package.json; printing raw contents)"
        Get-Content -LiteralPath $packageJsonPath | Add-Content -Path $OutputFile
    }
}
elseif (Test-Path -LiteralPath $requirementsPath) {
    Write-Line "Python Dependencies (requirements.txt):"
    Get-Content -LiteralPath $requirementsPath | Add-Content -Path $OutputFile
}
else {
    Write-Line "No dependency file (e.g., package.json, requirements.txt) found."
}
Write-Line

# 4) Summary
Write-Section "Summary"
Write-Line ("Project directory: {0}" -f $Root)
Write-Line ("Output file: {0}" -f (Resolve-Path -LiteralPath $OutputFile).Path)
Write-Line "Done!"

# Console confirmation
Write-Host "Project information has been extracted to $OutputFile"

Further Reading

GitHub Copilot

Gitingest

Repomix

Claude GitHub Integration

I

Indie4Tune Team

Writer and indie app developer passionate about creating tools that solve real problems. Follow along on the journey of building apps that matter.

Join the Movement

Join creators and thinkers who believe in better digital tools. Get updates, behind-the-scenes stories, and early access to new releases.

No spam. Unsubscribe at any time. We respect your privacy.