fedit — Fast File Editor for the Terminal
MCP serverFiles & storageGo-based MCP server for surgical file editing: anchored insert, delete, replace, move, copy.
Unavailable. This server has no hosted endpoint yet, so ahel can't serve it.
Add to setup to save this item as a reference. ahel cannot run it, and signing in will not install it.
Getting started
- Save this item in Your setup as a reference.
- Read the source or reference documentation for its setup requirements. Saving it here does not connect it to your AI.
- Check this page for availability before trying to install it through ahel.
From the project's README
As published by amalexico/fedit in README.md.
A zero-dependency CLI tool for surgical file edits from the command line. No interactive editors. No sed/awk gymnastics. Just simple, predictable operations with built-in verification.
Built for sysadmins, DevOps engineers, and anyone who scripts config changes.
go install github.com/amalexico/fedit@latest
Why fedit?
- One binary, zero dependencies — pure Go, runs everywhere
- 17 language mappers — see the structure of any file before editing
- -v flag — verify every mutation before moving on
- Line-aware — no regex surprises, no "which match did it hit?"
- Stream engine — process multi-GB files line-by-line with atomic integrity
- Field extraction — pull CSV/TSV column N without awk
- Safe — no in-place unless you say so, never touches files you did not name
Install
Go install (recommended):
go install github.com/amalexico/fedit@latest
Or download the binary from GitHub Releases and put it in your PATH.
Verify:
fedit -file /etc/hostname -op show
Quick Start
# See what is in a file
fedit -file config.yaml -op show
# See just lines 10-25
fedit -file config.yaml -op show -line 10 -end 25
# Find every line containing "timeout"
fedit -file config.yaml -op find -match "timeout"
# See the structure of a Go file
fedit -file main.go -op map -lang go
# Replace line 42 with new content
fedit -file config.yaml -op replace -line 42 -end 42 -text "timeout: 60s" -v
# Insert a line after every occurrence of "server {"
fedit -file nginx.conf -op insertafter -match "server {" -text " include security.conf;" -v
# Move a function block before another (content-matched, atomic)
fedit -file main.go -op move -match "func OldHelper(" -end 45 -beforematch "func NewHelper(" -v
# Copy a config block and paste it 3 times at a new location
fedit -file values.yaml -op copy -line 50 -end 65 -after 200 -times 3 -v
# Extract column 2 from a TSV file (v1.4+)
fedit -file data.tsv -op fields -col 2
# Write content with literal backslashes — no \n escape expansion (v1.6.0)
fedit -file config.txt -op writeraw -text "path=C:\\Users\\admin"
# Hex-encode tricky text to sidestep shell quoting (v1.6.0)
# fwencode produces the hex; fedit decodes it before writing
fedit -file config.txt -op write -texthex 706174683d2f746d70
# Overwrite a file cleanly then insert new content (v1.6.0)
fedit -file config.txt -op insert -line 0 -cleanfirst -text "# regenerated"
# Get bare line numbers for scripting (v1.6.0)
fedit -file main.go -op find -match "TODO" -x 2>$null
# Regex replace on a multi-GB log without loading it into memory (v1.4+)
fedit -file huge.log -op replaceall -match 'ERROR' -text 'WARN' -stream
All Operations
show — Display file contents
# Entire file
fedit -file app.conf -op show
# Lines 50-75 only
fedit -file app.conf -op show -line 50 -end 75
# Last 10 lines
fedit -file app.conf -op show -line -10:
# Lines 50 to 5th from end
fedit -file app.conf -op show -line 50 -end -5
# Lines 100-103 (relative range)
fedit -file app.conf -op show -line 100:+3
# Show from one anchor to another (no line numbers needed)
fedit -file config.go -op show -match "func Start" -endmatch "func End"
find — Search for lines matching a substring
# Find all lines containing "ERROR"
fedit -file /var/log/app.log -op find -match "ERROR"
# Output includes context lines and occurrence numbers
# Use -nth to target a specific match in other operations
Pro tip: Run find first to get line numbers, then use replace or delete with exact lines.
insert — Insert content after a line number
# Insert a comment after line 1
fedit -file script.sh -op insert -line 1 -text "# Added by deploy script" -v
# Insert multiple lines from a file
fedit -file config.yaml -op insert -line 10 -textfile extra-config.yaml -v
insertafter — Insert after a matching line (RECOMMENDED)
# Add a firewall rule after the matching comment
fedit -file iptables.rules -op insertafter -match "# Custom rules" -text "-A INPUT -p tcp --dport 8080 -j ACCEPT" -v
# Target the 2nd occurrence
fedit -file nginx.conf -op insertafter -match "server {" -nth 2 -text " listen 8443 ssl;" -v
# Target the last occurrence
fedit -file docker-compose.yml -op insertafter -match "volumes:" -nth -1 -text " - /data:/data" -v
insertbefore — Insert before a matching line (RECOMMENDED)
# Add a header before the first route definition
fedit -file routes.rb -op insertbefore -match "get '/'" -text " # === Public Routes ===" -v
# Insert a dependency before the closing bracket
fedit -file package.json -op insertbefore -match "}" -nth -1 -textfile new-deps.txt -v
replace — Replace a line range with new content
# Replace a single line
fedit -file config.ini -op replace -line 15 -end 15 -text "max_connections = 200" -v
# Replace lines 30-35 with content from a patch file
fedit -file server.conf -op replace -line 30 -end 35 -textfile patched-block.txt -v
# Replace a section by content anchors (no line numbers needed)
fedit -file CHANGELOG.md -op replace -match "## v1.6" -endmatch "## v1.5" -textfile new-section.txt -v
replaceall — Global find-and-replace
# Change all occurrences of old domain to new
fedit -file nginx.conf -op replaceall -match "old.example.com" -text "new.example.com" -v
# Update a version string everywhere
fedit -file Makefile -op replaceall -match "1.1.0" -text "1.2.0" -v
---
### fields -- Extract a column from delimited files (v1.4.0)
```bash
# Extract column 2 from a tab-separated file (default delimiter: tab)
fedit -file data.tsv -op fields -col 2
# Extract the third field from a CSV
fedit -file report.csv -op fields -col 3 -delim ","
# Extract usernames from /etc/passwd (colon-delimited)
fedit -file /etc/passwd -op fields -col 1 -delim ":"
Output goes to stdout for piping. Lines shorter than -col are skipped silently.
Always streaming -- no memory limit regardless of file size.
-stream -- Large-file streaming mode (v1.4.0)
Add -stream to replaceall or find to process files line-by-line without
loading them into memory. 10 MB per-line buffer handles JSON blobs and minified files.
Atomic integrity: writes to a temp file then renames -- original is untouched on interruption.
# Replace a pattern in a multi-GB log file
fedit -file server.log -op replaceall -match "10.0.0.1" -text "10.0.0.2" -stream
# Regex replace in a huge file with capture groups
fedit -file big.csv -op replaceall -match-regex 'id_(\d+)' -text 'ID_$1' -stream
# Streaming find -- grep-style output to stdout
fedit -file huge.log -op find -match "FATAL" -stream
Supported with -stream: replaceall (literal and regex), find.
Not supported: move, copy, map (these require full file structure in memory).
writeraw — Write without escape expansion
# Write a Windows path without double-escaping backslashes
fedit -file config.ini -op writeraw -text "basedir=C:\\Program Files\\App"
# Write content from a file as-is
fedit -file output.txt -op writeraw -textfile template.txt
Unlike write, writeraw treats \n as two characters (backslash + n), not a newline.
writelines — Write lines interactively from stdin
fedit -file notes.txt -op writelines
# Type lines at the > prompt, Ctrl+Z (Windows) or Ctrl+D (Unix) to finish
-texthex — Hex-encoded input (v1.6.0)
Encode text to hex first (e.g. with fwencode), then pass the hex string as -text.
Eliminates all shell-quoting issues with special characters.
# Decode hex string and write — no quoting gymnastics needed
fedit -file deploy.sh -op write -texthex 23212f62696e2f62617368
-cleanfirst — Truncate before writing (v1.6.0)
# Clear the file then insert fresh content at line 0
fedit -file output.txt -op insert -line 0 -cleanfirst -text "# regenerated"
-x — Machine-readable output (v1.6.0)
# Get bare line numbers from find (stdout only, no context noise)
fedit -file main.go -op find -match "TODO" -x 2>$null
# Extract CSV column with no stats footer
fedit -file data.csv -op fields -col 2 -delim "," -x
v1.5.0: HCL/Terraform block mapper (-lang hcl)
Move, copy, and refactor Terraform blocks by name — no line numbers needed.
Accepts -lang hcl, -lang tf, or -lang terraform (all equivalent).
Supported block types: resource, data, module, provider, variable,
output, locals, terraform, moved, import, check.
# Move a resource block before another
fedit -file main.tf -op move -block 'resource "aws_instance" "web"' \
-beforeblock 'resource "aws_s3_bucket" "data"' -lang hcl -v
# Copy a variable definition (scaffold new variable from existing)
fedit -file variables.tf -op copy -block 'variable "instance_type"' \
-after 20 -lang hcl -v
# Reorder provider blocks
fedit -file providers.tf -op move -block 'provider "google"' \
-beforeblock 'provider "aws"' -lang hcl -v
Nested blocks (e.g. ingress {} inside a resource) are correctly ignored —
only top-level blocks are matched.
v1.5.0: Nix block mapper (-lang nix)
Move and copy top-level attribute bindings in Nix expression files.
Handles attribute sets (name = { }), lists (name = [ ]), and
dotted attributes (programs.git = { }).
# Reorder home-manager program configs
fedit -file home.nix -op move -block "programs.git" \
-beforeblock "programs.ssh" -lang nix -v
# Copy a service config as a scaffold
fedit -file configuration.nix -op copy -block "services.nginx" \
-after 50 -lang nix -v
move — Move a line range to a new position
# Move lines 100-120 to after line 200 (explicit range)
fedit -file server.go -op move -line 100 -end 120 -after 200 -v
# Move a function block to before another function (content-matched)
fedit -file routes.go -op move -match "func OldHelper(" -end 45 -beforematch "func NewHelper(" -v
# Swap two nginx server blocks
fedit -file nginx.conf -op move -match "server {" -endmatch "# end server 1" -aftermatch "# end server 2" -v
# Cut once, scaffold 3 copies at destination
fedit -file main.go -op move -line 5 -end 12 -after 100 -times 3 -v
Rules:
- Destination may not overlap the source range — fedit reports a precise error with line numbers.
-times N: cut once, paste N times. Net delta = blockSize × (N−1). Default times=1 = zero delta.
copy — Copy a line range to a new position
# Copy a config block to after a section header
fedit -file values.yaml -op copy -line 50 -end 65 -aftermatch "# staging" -v
# Duplicate a test fixture 10 times for parameterised tests
fedit -file fixtures_test.go -op copy -match "func TestCase(" -end 30 -after 200 -times 10 -v
# Reorder Python classes (copy source before target; overlap is allowed)
fedit -file processor.py -op copy -match "class ModuleProcessor_15" -endmatch "class ModuleProcessor_16" -beforematch "class ModuleProcessor_13" -v
Rules:
- Snapshot semantics: source range is read once before any writes. All N copies are identical clones of the original, even when destination overlaps source.
- Net delta = blockSize × times.
---
### delete — Remove lines
```bash
# Delete a single line
fedit -file hosts -op delete -line 12 -end 12 -v
# Delete a block (lines 40-55)
fedit -file config.yaml -op delete -line 40 -end 55 -v
write — Create or overwrite a file
# Create a new file
fedit -file /tmp/note.txt -op write -text "Deployment started" -v
# Write multi-line content from another file
fedit -file /etc/motd -op write -textfile new-motd.txt -v
map — Structural overview of a file
# Map a Go file — see all functions, types, imports
fedit -file main.go -op map -lang go
# Map a Dockerfile — see stages and instructions
fedit -file Dockerfile -op map -lang dockerfile
# Map a Makefile — see variables, targets, duplicates
fedit -file Makefile -op map -lang makefile
Supported Map Languages (17)
| Language | Key Structures Detected |
|---|---|
| go | package, imports, types, interfaces, functions |
| python | imports, classes, functions, decorators |
| javascript | imports, exports, classes, functions, arrows |
| typescript | (same as javascript) |
| css | imports, custom properties, selectors, @media, @keyframes |
| rust | use, mod, struct, enum, trait, impl, fn, macro_rules! |
| java | package, imports, classes, interfaces, enums, methods |
| csharp | using, namespace, classes, interfaces, records, properties |
| html | doctype, head/body, headings, scripts, links, forms, ids |
| sql | CREATE, ALTER, DROP, INSERT, SELECT, indexes, triggers |
| yaml | document separators, top-level keys |
| toml | tables, array tables, top-level keys |
| markdown | headings, code blocks, links |
| ruby | requires, modules, classes, methods, attributes |
| php | namespace, use, classes, interfaces, traits, functions |
| dockerfile | FROM stages, all instructions |
| makefile | includes, variables, .PHONY, targets |
All mappers detect duplicates and flag them with warnings.
Flags Reference
| Flag | Description |
|---|---|
| -file PATH | Target file (required) |
| -op OP | Operation to perform (required) |
| -line N | Starting line number (1-based); N:+M=range, -N=from end, -N:=last N lines, :=EOF |
| -end N | Ending line (for ranges); -N counts from end of file |
| -text "s" | Inline text content |
| -textfile F | Read content from a file |
| -match "s" | Substring to search for |
| -nth N | Which occurrence (default 1, -1 = last) |
| -lang LANG | Language for map operation |
| -v | Verify: show affected lines after edit |
| -endmatch "s" | Content-anchor end of range (show/replace/delete/move/copy) |
| -quiet | Suppress stdout on success; exit code signals result |
Real-World Examples
Patch an Nginx config in a deploy script
#!/bin/bash
# Update upstream server and reload
fedit -file /etc/nginx/conf.d/app.conf \
-op replaceall \
-match "server 10.0.1.50:8080" \
-text "server 10.0.1.51:8080" -v
nginx -t && systemctl reload nginx
Add a cron job to crontab
fedit -file /etc/crontab \
-op insertafter \
-match "# Custom jobs" \
-text "0 2 * * * root /opt/backup.sh" -v
Bulk update version in multiple files
for f in Makefile config.yaml package.json; do
fedit -file "$f" -op replaceall -match "1.1.0" -text "1.2.0" -v
done
Inspect a Dockerfile before editing
fedit -file Dockerfile -op map -lang dockerfile
# See the structure, then surgically edit:
fedit -file Dockerfile -op insertafter -match "FROM alpine" -text "RUN apk add --no-cache curl" -v
Remove a block from a config
# First, find the lines
fedit -file app.conf -op find -match "deprecated-feature"
# Output says lines 44-49, so:
fedit -file app.conf -op delete -line 44 -end 49 -v
PowerShell workflow (Windows sysadmins)
# Set an alias
$f = "C:\tools\fedit.exe"
# Find all TODO comments in Go code
& $f -file main.go -op find -match "TODO"
# Replace a config value
& $f -file config.toml -op replaceall -match 'debug = true' -text 'debug = false' -v
# Map a file to understand its structure
& $f -file main.go -op map -lang go
Tips
- Always use -v on mutations — it costs nothing and saves you from blind edits
- Use find before replace — get the exact line numbers first
- Prefer insertafter/insertbefore over insert — matching is more resilient than hardcoded line numbers
- Use -nth -1 to target the last occurrence of a match
- Use -textfile for multi-line inserts — avoids shell quoting headaches
- map before editing unfamiliar files — see the structure first
LLM Benchmark
How well do current LLMs use fedit vs. rewriting whole files?
We tested Claude (Sonnet 4.6), ChatGPT (GPT-4o), and Gemini (2.5 Pro) on 7 realistic editing tasks across files of 565-1206 lines. Each model was tested twice per task: once asked to output the whole file ("raw"), once asked to output fedit commands only ("fedit").
Results
Legend: PASS+ = optimal one-line solution | PASS = correct | PASS* = correct content, formatting artifact | PARTIAL = correct intent, off-by-one or fragile | FAIL = wrong output
| Test | File | Task | Claude raw | Claude fedit | GPT raw | GPT fedit | Gemini raw | Gemini fedit |
|---|---|---|---|---|---|---|---|---|
| T1 | processor_600.go (575 L) | Insert method after specific struct method | PASS | PARTIAL | FAIL | PARTIAL | PASS | FAIL |
| T2 | config_800.yaml (1059 L) | Replace 24-line deployment block | PASS | PASS | FAIL | FAIL | PASS | FAIL |
| T3 | styles_500.css (565 L) | Find & delete CSS rule block | PASS | PASS | PASS* | FAIL | PASS* | FAIL |
| T4 | system_1000.go (980 L) | Global rename (36 occurrences) | PASS | PASS+ | FAIL | PASS+ | PASS* | PASS+ |
| T5 | analytics_700.py (682 L) | 3-step chain (insert + delete + replace) | PASS | PARTIAL | FAIL | FAIL | PASS | FAIL |
| T6 | dashboard_900.html (891 L) | Insert before 3rd matching button (-nth) | PASS | PARTIAL | FAIL | PASS+ | PASS | FAIL |
| T7 | engine_1200.go (1196 L) | Map + targeted insert after method | PASS | PASS | FAIL | FAIL | PASS | FAIL |
Top-line numbers
| Model | Raw mode | Fedit mode |
|---|---|---|
| Claude | 7/7 PASS | 4 PASS, 3 PARTIAL |
| ChatGPT | 1/7 PASS* | 2 PASS+, 1 PARTIAL, 4 FAIL |
| Gemini | 7/7 PASS* | 1 PASS+, 6 FAIL |
Key findings
1. ChatGPT cannot output large files reliably.
6 of 7 raw tests truncated. The most striking failure was T6, where it inserted
the literal placeholder line [... TRUNCATED FOR BREVITY ...] into otherwise
valid HTML — a uniquely dangerous failure mode where output looks structurally
complete but contains placeholder strings. T7 truncated 1206 lines down to 166.
2. LLMs hallucinate line numbers — and it gets worse with chain length. Gemini's line-number errors grew across the suite: off by 36-56 lines on T2 (single replace), 45 lines on T3, then 73 lines on T5 (3-step chain). ChatGPT showed similar drift on T5. Claude was the only model that produced runnable line-numbered commands consistently.
3. Content-matching ops are immune to the hallucination class.
Gemini failed every fedit test that required line numbers (T1, T2, T3, T5, T6,
T7), but PASSED T4 — which used replaceall with a content match. Same model,
same task complexity, dramatically different reliability. The bottleneck is
counting, not understanding.
4. insertafter on a function declaration matches the OPENING line.
Models repeatedly tried insertafter -match "func MyFunc()" to insert content
AFTER the function ended. This is correct fedit behavior (it inserts after the
matched line) but inserts the new code INSIDE the function body. Workaround:
insertbefore the NEXT structural element. Confirmed in T1 and T7.
5. Even Claude flubs line-number direction.
T6: Claude used insert -line 30 to add a banner before the 3rd button at line
30. But insert -line N adds content AFTER line N. The correct command was
insertbefore -match "View Details" -nth 3. Even the strongest model gets
direction wrong about 1 in 6 single-step ops when reaching for line numbers.
6. -match is single-line only — and that's a feature.
ChatGPT (T3 fedit) tried to pass a multi-line CSS block as -match with literal
\n escapes. fedit doesn't interpret escapes in -match and matches only
single lines. This kept the operation safe (zero matches → no edit) rather than
allowing a fragile multi-line pattern that could easily mismatch.
7. Markdown rendering is a hidden adversary.
ChatGPT and Gemini outputs lost __name__ → name, __init__ → **init**,
and stripped CSS/Python indentation when rendered in chat UIs. The underlying
files (when downloaded directly) were correct. This affects copy-paste workflows
but not API integrations. For best results, use the model's "copy code"
button or download links — never select-and-copy from rendered output.
8. Three different models converged on the same one-liner for T4.
Claude, ChatGPT, and Gemini all independently produced
fedit -op replaceall -match "FetchUser" -text "GetAccount".
When the right tool is obvious, models reach for it. fedit's design surface
makes the right tool obvious for content-driven edits.
Recommendations for LLM-driven workflows
Based on these results, prefer content-matching operations over line-number operations when generating fedit commands from an LLM:
- Use
insertbefore -match "next anchor"instead ofinsert -line N - Use
replaceall -match "old" -text "new"instead ofreplace -line N -end M - Use
find -matchandshowto confirm line numbers before any line-numbered op - Reserve line-numbered ops for cases where an MCP-connected LLM has just run
fedit_findorfedit_showand has verified the line in context
For best results, give the LLM an MCP connection to fedit (see
MCP Server Mode) so it can fedit_find and fedit_show
before mutating. This eliminates the line-number hallucination class entirely
and was the path Claude consistently took when it had recon available.
Methodology
- Each test run in a fresh chat with the original file uploaded
- Prompts identical across models; only "raw" vs "fedit" framing differed
- Output saved verbatim, then diffed against ground truth via
Compare-Object - Ground truth verified by running fedit commands locally and re-reading output
- All 7 raw outputs that PASSED Compare-Object empty (byte-identical to ground truth): Claude T2, T3, T4, T5, T6, T7 + Gemini T5, T6, T7
PASS*indicates byte-difference from indentation-stripping in chat UI render, with content structurally correct (verified by re-running fedit ops on the saved file)
Test corpus
7 synthetic files (565-1206 lines) covering Go, YAML, CSS, Python, and HTML.
All test files, prompts, and ground-truth outputs are available in the bench/
directory of this repository.
MCP Server Mode
fedit includes a built-in Model Context Protocol (MCP) server, so AI coding assistants can use fedit as a tool for precise file edits.
fedit mcp
This starts a JSON-RPC 2.0 server on stdin/stdout. The server exposes all 14 editing operations as MCP tools:
Shortened here. Read the whole README on GitHub.
Signals
- GitHub stars
- 11
- Last commit
- Sep 2026
ahel review
S4low
published under kehsiaocuba's namespace; repository belongs to amalexico
Automated review, not a security audit. Ruleset v1.
Advanced
- Delivery
- fedit MCP server → your ahel connector (mcp.ahel.ai) → your AI.
- Item type
- mcp-server
- Key
io-github-kehsiaocuba-ux-fedit- Source
- github.com/amalexico/fedit
More in Files & storage
MCP server · wonderwhy-er
More in Files & storagelocal-mcp
MCP server · colibird-ai
More in Files & storageruntime
MCP server · withruntime
More in Files & storageopen-agreements
MCP server · open-agreements
More in Files & storageyungle
MCP server · heindewilde
More in Files & storagecarbone-mcp
MCP server · carboneio
More in Files & storage