🥞 fln
A local, explainable context compiler for AI coding agents. Retrieval without embeddings. Context without a server.
Power your agent
การติดตั้งจากผู้เผยแพร่ ไม่ใช่เอนด์พอยต์ของ PlugMCP
URL แบบรีโมตหรือคำสั่งบนเครื่องของคุณ? การติดตั้งสองแบบต่างกันอย่างไร
รันบน PlugMCP
A new server you create. It is not this listing's official endpoint. Use the publisher install when you want their URL and their credentials.
เปิด
fln analyzes your codebase, plans what to include, and emits a single AI-ready file — with diagnostics that explain every decision. Think tsc for LLM context: analyze → plan → emit, all local.
npx fln # or: npm i -g fln · bunx fln · brew install nesvet/tap/fln
fln # → my-app-1.2.0.md in the current directory
$ fln --no-ansi
✓ my-app-1.2.0.md (42 files, 12_840 tokens)
One markdown file — header, directory tree, backtick-safe fences. Paste into Claude, ChatGPT, Gemini, Grok, Cursor, or Copilot; pipe to a CLI LLM (fln --stdout | llm "..."); or serve over MCP.
# Codebase Snapshot: demo-app
Generated: 2026-07-06 17:30
Files: 6 | Directories: 3
---
## Directory Tree
```text
├── README.md
├── package.json
├── src
│ ├── index.ts
│ ├── helper.ts
│ └── utils.ts
└── tests
└── index.test.ts
```
---
## Source Files
### src/index.ts
```ts
import { helper } from "./helper";
import { format } from "./utils";
export function main(): string {
return format(helper());
}
```
--relevant) without embeddingsIf you use LLMs on real projects, you've hit these limits:
fln treats codebase context the way tsc treats TypeScript: analyze, plan, emit — with diagnostics (why, doctor, plan, diff) and MCP.
JIT agent retrieval (tool calls, embeddings, live search) is great for interactive exploration. fln is the complementary AOT snapshot compiler: it builds a deterministic context spine before the agent starts — structure-based retrieval (imports, priority, token budgets), no embeddings, no server. Same input → same snapshot; CI-friendly; offline.
why/doctor/plan/diff, --relevant, --stdin--compress, watch mode, web UIhub→ingest URL trick@codebase — live IDE retrieval on large reposNot mutually exclusive: fln and repomix both produce paste-ready files; fln adds the compiler/diagnostics layer.
fln plan assigns fidelity per file and projects tokens before you spend the budget. With --relevant, only the import-graph neighborhood of the seed is included:
$ fln plan --relevant src/cli/index.ts --budget 200000
# Context Plan: .
Budget: 200,000 tokens
Projected: 67,149 tokens
Files included: 100
Files omitted: 1
## Included files
src/api/index.ts — ~239 tokens (entry point — high priority)
src/cli/index.ts — ~89 tokens (seed file)
src/cli/output/index.ts — ~28 tokens (entry point — high priority)
...
Full output: assets/demo-plan.md. Use --format json for CI/agents. Formal schema: schema/fln-plan.json ($id: https://fln.nesvet.dev/schema/plan).
fln plan --budget 200000
fln plan --relevant src/cli/index.ts --budget 200000
fln plan --format json
fln why .env # why is .env excluded?
fln why src/index.ts # why is index.ts included?
fln why .env --format json # machine-readable for CI/agents
fln doctor . # config, git, scan stats, token estimate
fln doctor --max-tokens 200000 # warn if over budget
fln doctor --format json --recommend-budget 200000
fln mcp # stdio MCP server
fln mcp --http --port 3000 # Streamable HTTP
fln why is a first-class path-decision CLI with stable reasons (gitignore, security, size, whitelist, …) and JSON for agents.
Resources: fln_file://{path}, fln_snapshot://{name}.
{
"mcpServers": {
"fln": { "command": "fln", "args": ["mcp"] }
}
}
--stdin force-includes piped paths (like -i), then prunes the tree to exactly that set. Security still applies — detected secrets are never embedded:
git ls-files | fln --stdin -o snapshot.md
git ls-files --others | fln --stdin -o untracked.md
git diff --name-only HEAD~1 | fln --stdin --stdout
rg -l TODO | fln --stdin --stdout
git diff --name-only main | fln plan --stdin --budget 50000
fln --copy # clipboard (32 MiB default; FLN_COPY_MAX_BYTES to override)
fln --stdout | llm "What are the biggest architecture issues here?"
fln --stdout | pbcopy # fallback when --copy isn't available
fln --since main --ext ts,tsx
fln --since main --diff-hunks
fln --relevant src/index.ts --outline
fln --banner-file .prompt.md
fln --banner "Review this codebase for security vulnerabilities."
Performance: linux-x64 CI baselines for the medium fixture (5000 files) — dry-run ~1.1s, full flatten ~2.4s (median; gate = baseline +10%). Details: benchmarks/README.md.
.gitignore; skips binaries/lockfiles; configurable size limitsvendor/ deprioritized)--verbose extension breakdown; self-aware (skips prior fln output)package.json, Cargo.toml, pyproject.toml, pom.xml, go.mod, …md / json; --compress / --outline (custom line-based signatures, not Tree-sitter)--max-total-size graceful omit; --strict-limits for CI; doctor --recommend-budget--strict-toctou); --annotate-tree; --collect-todo (same content pass)--dry-run; namespace API: fln(), .inspect(), .explain(), .doctor(), .plan(), .diff(), .mcp()omittedFiles in JSON (flat, capped, all reasons)flatten, why, doctor, plan, diff, mcp). fln upgrade is the explicit exception.~/.config/fln/usage.json may store runCount / lastRun only (sponsor message on runs 5 and 25). Hide: FLN_NO_SPONSOR=1 or --no-sponsor-message. Skip write: --no-local-state.npx fln # run once
bunx fln
npm install -g fln
bun add -g fln
# Native binary — no Node required
curl -fsSL https://fln.nesvet.dev/install | sh
powershell -c "irm fln.nesvet.dev/install.ps1 | iex"
brew install nesvet/tap/fln
# Homebrew 6.0+: trust the formula on first use
brew trust --formula nesvet/tap/fln
fln upgrade # binary self-update (sha256 + optional cosign)
Pin version / custom dir (macOS/Linux):
curl -fsSL https://fln.nesvet.dev/install | FLN_VERSION="<version>" INSTALL_DIR="$HOME/.local/bin" sh
Windows:
$env:FLN_VERSION = "<version>"
$env:INSTALL_DIR = "$env:LOCALAPPDATA\fln\bin"
powershell -c "irm fln.nesvet.dev/install.ps1 | iex"
Manual GitHub Release:
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/fln
Completions (bash / zsh / fish / PowerShell) — from a clone: source completions/_fln (zsh), source completions/fln.bash, etc. After npm i -g fln: source "$(npm root -g)/fln/completions/_fln". Regenerate: bun run generate:completions.
fln [directory] [...flags]
fln init [--overwrite]
fln why <path> [directory] [...flags]
fln doctor [directory] [...flags]
fln plan [directory] [--budget <n>] [--relevant <seed>] [...flags]
fln diff <before> <after> [...flags]
fln diff --since <ref>
fln mcp [directory]
fln upgrade
fln # → my-app-1.2.0.md
fln . -o context.md
fln src -o . # scan src/, write to project root
fln -e "*.test.ts" -e "fixtures/"
fln -e "*.md" -e '!README.md'
fln --ext ts,tsx --since HEAD~1
fln -i "src/generated/schema.ts" # force-include gitignored file
fln --only "**/*.ts"
fln why .env --include-hidden
fln --dry-run --verbose
fln --format json -o snapshot.json
fln mcp
Files over --max-file-size are skipped unless force-included (-i / --stdin); content streams at render. See SECURITY.md.
Canonical list: fln --help. Config: fln.json / schema/fln.json. API: below.
Multi-word flags accept camelCase aliases (e.g. --maxFileSize, --noTree) — docs use kebab-case.
Subcommands
Output
Filtering
Content
Doctor: --recommend-budget <n>. MCP: --http, --port <n> (default 3000).
Logging: -q / -V / --debug / --no-ansi / --no-sponsor-message / --no-local-state / -v / -h.
Quote globs:
"*.test.ts". Un-exclude:-e "*.md" -e '!README.md'.
fln init
Writes fln.json with JSON Schema IntelliSense ($schema: https://fln.nesvet.dev/schema).
{
"$schema": "https://fln.nesvet.dev/schema",
"output": "output.md",
"exclude": [],
"include": [],
"only": [],
"includeHidden": false,
"maxFileSize": "10mb",
"maxTotalSize": "0",
"maxTokens": 0,
"maxContentTokens": 0,
"tokenModel": "estimate",
"strictLimits": false,
"encoding": "auto",
"format": "md",
"followSymlinks": false,
"overwrite": false
}
Additional keys (gitignore, banner, securityPatterns, …): schema/fln.json and API. Patterns are gitignore-style relative to input; CLI merges with the file (--ignore-config skips it).
Fresh codebase.md on every push — download anytime to chat about the exact state of main or a 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@v7
- name: Generate snapshot
run: npx fln . -o codebase.md -w --no-ansi
- uses: actions/upload-artifact@v7
with:
name: codebase-snapshot
path: codebase.md
retention-days: 7
Pre-commit budget guard:
# .husky/pre-commit
npx fln . --dry-run --max-total-size 5mb
npm install fln
import { fln } from "fln";
const result = await fln({
input: "./src",
output: "snapshot.md",
exclude: ["*.test.ts", "fixtures/"],
onProgress: (current, total) => {
process.stdout.write(`\r${current}/${total} files`);
},
});
console.log(`${result.filesIncluded} files → ${result.outputPath}`);
console.log(`~${result.outputTokenCount.toLocaleString()} tokens`);
const { root, stats } = await fln.inspect({ input: "./src", dryRun: true });
const decision = await fln.explain({ path: ".env", input: "./src" });
const report = await fln.doctor({ input: "./src" });
const planResult = await fln.plan({
input: "./src",
budget: 200_000,
relevant: ["src/index.ts"],
});
const diffResult = await fln.diff({ before: "snapshot-v1.md", after: "snapshot-v2.md" });
await fln.mcp({ defaultInput: "./src" });
Formal schemas for JSON: plan ($id: https://fln.nesvet.dev/schema/plan), diff ($id: https://fln.nesvet.dev/schema/diff).
Matches FlnOptions / FlnResult / FlnInspectResult / FlnMcpOptions in the package types.
Options (FlnOptions)
MCP options (FlnMcpOptions)
Config file logLevel default in schema/fln.json is "normal" when using fln.json alone.
Diagnostics: fln why <path> from the CLI (--format json for agents/CI; not in fln.json). SDK: fln.explain().
fln doctor [directory] runs a dry-run scan (metadata only, no flatten file). Same filtering flags as flatten (-e, -i, --only, --since, --ext, --stdin, …).
Human output includes config path, git branch/dirty, file counts, estimated size/tokens (±20% vs real flatten), top extensions, and warnings (oversized files, security paths in tree, --max-tokens budget). With --since and no matching changes, prints the same early message as fln and exits 0.
fln doctor .
fln doctor --format json --max-tokens 500000
fln doctor --format json --recommend-budget 200000
JSON shape: schemaVersion: 1, config (loaded, path, optional ignored when --ignore-config), git, scan, estimate, extensions, warnings, optional recommend (exclude, projectedTokens, omittedCount). Formal schema: schema/fln-doctor.json ($id: https://fln.nesvet.dev/schema/doctor).
import { fln, toFlnWhyJson } from "fln";
const report = await fln.doctor({
input: projectDir,
recommendBudget: 200_000,
});
const decision = await fln.explain({ path: ".env", input: projectDir });
// why CLI JSON: { schemaVersion: 1, input: "<abs dir>", decision: { relativePath, included, reason, detail? } }
fln.doctor() does not accept --no-local-state or --no-sponsor-message — those are CLI-only. Programmatic sponsor status reflects usage.json and FLN_NO_SPONSOR only.
--format json emits a structured document. Top-level root is the FileNode tree; options.tree / options.contents are the boolean flags used for that run. The files array is omitted when --no-contents is set.
Formal schema: schema/fln-output.json ($id: https://fln.nesvet.dev/schema/output).
fln --format json --max-tokens 200000 -o snap.json
jq '.omittedFiles[] | select(.reason=="tokenLimit") | .path' snap.json
With fln why --format json, errors use toFlnFailureJson on stderr ({ ok: false, error: { code, message, hint? } }).
Inspect (fln.inspect) — same options as fln(), scan only. Returns FlnInspectResult: projectName, root (FileNode with skipReason), stats.
Programmatic API surface: operations on the namespace only — fln(), fln.inspect(), fln.explain(), fln.doctor(), fln.plan(), fln.diff(), fln.mcp(). Standalone: VERSION, toFlnWhyJson, toFlnDoctorJson, toFlnPlanJson, toFlnDiffJson, toFlnFailureJson, formatPlanText, formatDoctorText, formatDiffText, FlnError, and types.
Result (FlnResult): projectName, filesIncluded, filesScanned, directories, binary, skipped, errors, totalSizeBytes, outputSizeBytes, outputTokenCount, outputPath ("-" for stdout, "" when dryRun or copy).
Error codes (FlnError)
import { fln, FlnError } from "fln";
try {
await fln({ input: dir });
} catch (error) {
if (error instanceof FlnError)
console.error(error.code, error.hint ?? error.message);
throw error;
}
How is fln different from repomix?
Both produce a paste-ready file. repomix is a feature-rich packer (remote repos, Tree-sitter compression, watch mode). fln is a compiler with diagnostics — why, doctor, plan, diff, --relevant, and an MCP server. Pick repomix for one-shot web-chat paste or remote repos; pick fln when you need reproducibility, CI guards, or explainability. See Compare.
Do I need embeddings or a server?
No. fln is fully local — zero network during a normal run. --relevant walks the import graph with a zero-dependency line-based parser (TS/JS/Py/Go/Rust/Java/C) — structure-based retrieval, not similarity search.
Does it work with MCP agents?
Yes. fln mcp starts an MCP server (stdio by default; --http --port for Streamable HTTP) exposing fln_snapshot, fln_plan, fln_diff, fln_why, and fln_doctor to any MCP-aware agent (Claude Code, Cursor, Codex CLI, VS Code). See Workflows.
Is it safe to pipe secrets?
Detected secrets are never embedded, even with force-include. fln skips sensitive paths (.env, keys, credentials) by pattern, and runs entropy + known-secret detection (AWS, Google, GitHub, Stripe, Slack, Azure, GitLab, JWT, PEM) on file headers. A force-included secret file stays in the tree with skipReason: "security" — content is omitted. Detection is not a guarantee — review output before sharing. See SECURITY.md.
Does --stdin bypass .gitignore?
Yes — intentionally. --stdin force-includes the piped paths (bypassing .gitignore, exclude, and hidden filters, like -i), then prunes the tree to exactly that set. That is what makes git ls-files --others | fln --stdin work for untracked files. Security patterns still apply; paths resolving outside the input directory are dropped.
Why AOT instead of JIT retrieval?
They solve different problems. JIT (Cursor @codebase, agentic search) is great for interactive exploration on large repos. AOT (fln) is great for reproducible snapshots, CI context guards, budget planning, and offline workflows — and for explainability. You decide what to include before the agent starts. They're complementary; many stacks use both.
How do I update fln?
npm install -g fln or bun add -g flnbrew upgrade nesvet/tap/flncurl …/install): fln upgrade — downloads the latest GitHub Release, verifies sha256 (required), optionally verifies cosign when cosign is on PATH.--token-model controls how fln estimates token counts for budgets, doctor, and diff deltas.
Use gpt-4o or gpt-5 when targeting OpenAI models. Use estimate for quick checks. Markdown snapshots record the model in the header; fln diff uses it for token deltas.
Real outputs from examples/:
Node.js — requires >=22.0.0, ESM-only ("type": "module"). Install via npm i -g fln or run with npx.
Bun — requires >=1.4.0. Install via bun add -g fln or run with bunx.
Standalone binary — no runtime required. Install via the curl / PowerShell one-liner above.
Unknown legacy keys in fln.json are rejected with Unknown config key. See CHANGELOG.md for the full 2.0 breaking list.
fln is free, open-source, and maintained by one developer.
If it saves you time or improves your AI workflow:
PRs and issues are welcome. Local gate: bun run verify (mirrors CI). See CONTRIBUTING.md for setup and AGENTS.md for architecture and invariants.
MIT © Eugene Nesvetaev
Local, explainable context compiler for AI coding agents. Analyze → plan → emit optimal context — with why/doctor diagnostics. No embeddings, no server.
เครื่องมือ
ยังไม่มีรายการเครื่องมือ เซิร์ฟเวอร์แบบรีโมตจะได้รายการหลังการตรวจสอบสถานะครั้งแรก
FAQ
คัดลอกคอนฟิก stdio สำหรับ Cursor, Claude Desktop, Claude Code หรือ VS Code ได้ในหน้านี้ คอนฟิกนี้ใช้การติดตั้งของผู้เผยแพร่ ไม่ใช่พร็อกซีของ PlugMCP
ระเบียนนี้ไม่ได้ระบุตัวแปรสภาพแวดล้อมที่จำเป็น
Fln ทำงานแบบโลคัลผ่าน stdio
ตรวจสอบล่าสุดเมื่อ 2026-10-28 Local, explainable context compiler for AI coding agents. Analyze → plan → emit optimal context — with why/doctor diagnostics. No embeddings, no server.