Your entire codebase → one AI-ready file.
Stop wrestling with file pickers and attachment limits — feed your whole project to any LLM in one shot.
npx flnWorks with Claude, ChatGPT, Gemini, Grok, Cursor, Copilot, and any AI tool.
fln (short for flatten) is language-agnostic by design: TypeScript, Python, Rust, Go, Java, mixed monorepos — it treats everything as plain text, auto-detects project metadata from ecosystem manifests, respects .gitignore, and skips binaries automatically.
If you use LLMs for real projects, you've hit these limits:
- Context windows — large projects don't fit
- Upload friction — selecting dozens of files for every session
- Partial understanding — AI sees fragments, not the architecture
- Manual prep — repeating the same setup context again and again
fln removes that overhead.
It turns your project into a single, structured snapshot that LLMs can actually reason about.
→ Full-context refactoring
Ask architectural questions impossible file-by-file:
"Where is the real coupling here?"
"What should be split into modules?"
→ Instant onboarding
One Markdown file instead of "start by opening these 12 folders." Perfect for reading code on a tablet or onboarding new developers without an IDE.
→ Project-level code reviews
Detect patterns, inconsistencies, and risks across the entire codebase at once.
→ Auditable snapshots
A single, clean artifact of your codebase state for security reviews, compliance audits, or legal records — without granting full repo access.
→ Dataset preparation
Generate clean, formatted data for RAG pipelines and fine-tuning custom models.
→ LLM-friendly diffs
Flatten → commit → flatten again. See how the whole project changed structurally.
fln --stdout | pbcopy # macOS
fln --stdout | wl-copy # Linux (Wayland)
fln --stdout | xclip -selection clipboard # Linux (X11)One command — your entire codebase is in the clipboard. Open any AI chat, paste, ask.
fln --stdout | llm "What are the biggest architecture issues here?"
fln --stdout | aichat "Write a CHANGELOG entry for the latest changes"
fln --stdout | sgpt "Suggest a refactoring plan for this codebase"# Everything changed since the last commit
fln --since HEAD~1
# Everything that differs from main
fln --since main
# Only changed TypeScript files (intersection, not union)
fln --since main --ext ts,tsx--since calls git diff --name-only under the hood. Zero config.
fln --ext ts,tsx # TypeScript only — dramatically reduces token count
fln --ext py # Python only
fln --ext rs # Rust only
fln --ext go # Go onlyPut your system prompt in a file — it will be prepended to the output and excluded from the directory tree:
fln --banner-file .prompt.md<!-- .prompt.md -->
You are a senior engineer reviewing a production codebase.
Identify architecture issues, suggest improvements, point out any bugs.Or inline:
fln --banner "Review this codebase for security vulnerabilities."Same for footers: --footer-file / --footer.
- ⚡ Fast parallel scanning — thousands of files in seconds
- 🎯 Smart filtering — respects
.gitignore, skips binaries and lock files, configurable size limits - 📁 Intentional file order —
README, entry points, and configs first;LICENSE,CHANGELOGlast. LLMs see the most important context first - 📊 Token count upfront — every run reports estimated tokens so you know what you're sending before you hit send
- 🔍 Extension breakdown —
--verboseshows token distribution by file type, so you know exactly what's eating your context window - 🔄 Self-aware — skips files previously generated by
fln, never recurses into its own output - 🛡️ Backtick-safe — if a file contains
```, fln automatically uses longer fences so the Markdown never breaks - 📐 Deterministic output — same input → same snapshot
- 🧠 Project metadata detection — output named
my-app-1.2.0.mdautomatically frompackage.json,Cargo.toml,pyproject.toml,pom.xml,go.mod,vcpkg.json,CMakeLists.txt - 🛠️ Two output formats —
mdfor humans,jsonfor tooling - 🔒 Fully local — zero telemetry, zero network calls, no data leaves your machine
npx fln # run once without installing
bunx fln
npm install -g fln
bun add -g flncurl -fsSL https://fln.nesvet.dev/install | shpowershell -c "irm fln.nesvet.dev/install.ps1 | iex"More installation options
Pin a specific version or install to a custom directory (macOS/Linux):
curl -fsSL https://fln.nesvet.dev/install | FLN_VERSION="<version>" INSTALL_DIR="$HOME/.local/bin" shWindows PowerShell:
$env:FLN_VERSION = "<version>"
$env:INSTALL_DIR = "$env:LOCALAPPDATA\fln\bin"
powershell -c "irm fln.nesvet.dev/install.ps1 | iex"Manual download from GitHub Releases:
curl -L "https://github.com/nesvet/fln/releases/latest/download/fln-macos-x64.tar.gz" | tar -xz -C /usr/local/bin
chmod +x /usr/local/bin/flnfln [directory] [...flags]
fln init [--overwrite]# Flatten the current directory → my-app-1.2.0.md
fln
# Specify input and output
fln . -o context.md
# Scan src/, save output to the project root
fln src -o .
# Source files only — no tests, no fixtures
fln -e "*.test.ts" -e "*.spec.ts" -e "fixtures/"
# Include all source files but exclude markdown — except README
fln -e "*.md" -e '!README.md'
# TypeScript source only
fln --ext ts,tsx
# Changed files since last commit
fln --since HEAD~1
# Tree only — no file contents
fln --no-contents
# Force-include a file that's in .gitignore
fln -i "src/generated/schema.ts"
# Preview what would be included, with per-extension breakdown
fln --dry-run --verbose
# Overwrite instead of creating codebase-1.md
fln -o codebase.md -w
# JSON output for programmatic use
fln --format json -o snapshot.jsonAll CLI flags
Output
| Flag | Description |
|---|---|
-o, --output <path> |
Output file or directory. Adds .md/.json if no extension given. Default: <n>-<version>.md |
-w, --overwrite |
Overwrite instead of adding numeric suffix |
--stdout |
Write to stdout instead of file (implies --quiet) |
--format <md|json> |
Output format (default: md) |
--dry-run |
Scan and report without writing anything |
Filtering
| Flag | Description |
|---|---|
-e, --exclude <glob> |
Exclude pattern — repeatable |
-i, --include <glob> |
Whitelist mode — only matching files are included, repeatable |
--ext <ext> |
Include only these extensions, e.g. ts,tsx,js |
--since <ref> |
Only files changed since git ref, e.g. HEAD~1, main |
--include-hidden |
Include hidden files and directories |
--no-gitignore |
Ignore .gitignore rules |
--max-size <size> |
Max individual file size, e.g. 10mb, 512kb |
--max-total-size <size> |
Max total size of all included files |
--follow-symlinks |
Follow symlinks while scanning |
Content
| Flag | Description |
|---|---|
--no-contents |
Exclude file contents (tree only) |
--no-tree |
Exclude directory tree |
--banner <text> |
Prepend text after the header |
--banner-file <path> |
Prepend file contents — relative to input, excluded from tree |
--footer <text> |
Append text at the end |
--footer-file <path> |
Append file contents — relative to input, excluded from tree |
--date <YYYY-MM-DD HH:mm> |
Fix the Generated date (useful for reproducible output) |
Logging & other
| Flag | Description |
|---|---|
-q, --quiet |
Minimal output |
-V, --verbose |
Verbose output with per-extension token breakdown |
--debug |
Debug output with full file list |
--no-ansi |
Disable colors |
--no-sponsor-message |
Hide support message (also: FLN_NO_SPONSOR=1) |
-v, --version |
Show version |
-h, --help |
Show help |
Note: Quote glob patterns to prevent shell expansion —
"*.test.ts", not*.test.ts.
To un-exclude a specific file, use negation in--exclude:-e "*.md" -e '!README.md'.
fln initGenerates .fln.json with full IntelliSense support in VS Code, WebStorm, and any editor with JSON Schema — autocomplete and validation out of the box, no extensions needed.
.fln.json reference
{
"$schema": "https://fln.nesvet.dev/schema",
"output": "snapshot.md",
"overwrite": false,
"excludePatterns": [ "dist/", "**/*.snap" ],
"includePatterns": [],
"includeHidden": false,
"gitignore": true,
"maxFileSize": "10mb",
"maxTotalSize": "0",
"includeTree": true,
"includeContents": true,
"format": "md",
"followSymlinks": false,
"logLevel": "normal",
"date": "2026-02-20 12:00",
"banner": "You are reviewing a production codebase.",
"bannerFile": ".prompt.md",
"footer": "End of snapshot.",
"footerFile": "docs/footer.md"
}Pattern format: gitignore-style globs relative to the input directory. Leading ./ is normalized. Use ! for negation (*.log + !important.log). Trailing slash src/ matches directories only. CLI flags always override the config file.
Fresh codebase.md on every push. Download it anytime to chat with LLMs about the exact state of your main branch or a specific PR:
# .github/workflows/codebase-snapshot.yaml
name: Snapshot Codebase
on:
push:
branches: [ "main" ]
pull_request:
jobs:
snapshot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Generate snapshot
run: npx fln . -o codebase.md -w --no-ansi
- uses: actions/upload-artifact@v6
with:
name: codebase-snapshot
path: codebase.md
retention-days: 7Fail the commit if the flattened codebase exceeds a size limit — ensures the project always fits in LLM context windows:
# .husky/pre-commit
npx fln . --dry-run --max-total-size 5mbnpm install flnimport { fln } from "fln";
const result = await fln({
input: "./src",
output: "snapshot.md",
excludePatterns: [ "*.test.ts", "fixtures/" ],
onProgress: (current, total) => {
process.stdout.write(`\r${current}/${total} files`);
}
});
console.log(`${result.files} files → ${result.outputPath}`);
console.log(`~${result.outputTokenCount.toLocaleString()} tokens`);Full API reference
Options
| Option | Type | Default | Description |
|---|---|---|---|
input |
string |
process.cwd() |
Directory to flatten |
output |
string |
auto | Output file path or directory. "-" for stdout |
overwrite |
boolean |
false |
Overwrite instead of numeric suffix |
excludePatterns |
string[] |
[] |
Glob patterns to exclude |
includePatterns |
string[] |
[] |
Glob patterns to force include |
includeHidden |
boolean |
false |
Include hidden files/dirs |
gitignore |
boolean |
true |
Respect .gitignore rules |
maxFileSize |
number | string |
"10mb" |
Max individual file size |
maxTotalSize |
number | string |
0 |
Max total size (0 = unlimited) |
includeContents |
boolean |
true |
Include file contents |
includeTree |
boolean |
true |
Include directory tree |
format |
"md" | "json" |
"md" |
Output format |
followSymlinks |
boolean |
false |
Follow symlinks |
date |
string |
current | Fixed YYYY-MM-DD HH:mm for Generated header |
banner |
string |
— | Text prepended after header |
bannerFile |
string |
— | File prepended (relative to input) |
footer |
string |
— | Text appended at end |
footerFile |
string |
— | File appended (relative to input) |
logLevel |
"silent" | "normal" | "verbose" | "debug" |
"silent" |
Log level |
ansi |
boolean |
false |
ANSI colors in log output |
onProgress |
(current, total) => void |
— | Progress callback |
Result
type FlnResult = {
projectName: string; // from package.json, pom.xml, Cargo.toml, etc.
files: number; // files included
directories: number; // directories scanned
binary: number; // binary files (shown as [BINARY FILE: X kb] in output)
skipped: number; // skipped — too large, generated by fln, or read errors
errors: number; // read errors
totalSizeBytes: number; // total input size
outputSizeBytes: number; // output file size
outputTokenCount: number; // estimated token count
outputPath: string; // absolute path ("-" for stdout)
};Real outputs from examples/:
Runtime compatibility
Node.js — requires >=18.3.0, ESM-only ("type": "module"). Install via npm i -g fln or run with npx.
Bun — requires >=1.0.0. Install via bun add -g fln or run with bunx.
Standalone binary — no runtime required. Install via the curl / PowerShell one-liner above.
fln is free, open-source, and maintained by one developer.
If it saves you time or improves your AI workflow:
- ⭐️ Star the repo — it genuinely helps discoverability
- 💙 Support on Patreon — keeps development going
PRs and issues are welcome. See CONTRIBUTING.md for setup and guidelines.
MIT © Eugene Nesvetaev