{"id":49203052,"url":"https://github.com/parcadei/fastedit","last_synced_at":"2026-04-27T20:00:38.688Z","repository":{"id":352958525,"uuid":"1216987200","full_name":"parcadei/fastedit","owner":"parcadei","description":"AST-aware fast code editing via local 1.7B model","archived":false,"fork":false,"pushed_at":"2026-04-23T23:00:29.000Z","size":2633,"stargazers_count":37,"open_issues_count":0,"forks_count":4,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-26T19:02:38.136Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/parcadei.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T12:37:18.000Z","updated_at":"2026-04-26T11:04:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/parcadei/fastedit","commit_stats":null,"previous_names":["parcadei/fastedit"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/parcadei/fastedit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parcadei%2Ffastedit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parcadei%2Ffastedit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parcadei%2Ffastedit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parcadei%2Ffastedit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/parcadei","download_url":"https://codeload.github.com/parcadei/fastedit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parcadei%2Ffastedit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32352406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-27T17:12:42.749Z","status":"ssl_error","status_checked_at":"2026-04-27T17:12:41.658Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-23T16:01:23.081Z","updated_at":"2026-04-27T20:00:38.644Z","avatar_url":"https://github.com/parcadei.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FastEdit\n\nAST-aware code editing powered by a fine-tuned 1.7B model. Diffs, SEARCH/REPLACE, and apply_patch all force the agent to repeat back old code to say *where* the edit goes. FastEdit uses tree-sitter to find the target by name — the agent writes only the change plus a line or two of context.\n\n### Agent output token savings\n\n| Model | Edit tool tokens | FastEdit tokens | Saved | Reduction |\n|-------|-----------------|-----------------|-------|-----------|\n| GPT-5.4 | 3,404 | 1,557 | 1,847 | **54.3%** |\n| Opus 4.6 | 4,286 | 2,291 | 1,995 | **46.5%** |\n| Opus 4.7 | 4,771 | 2,645 | 2,126 | **44.6%** |\n| Grok 4.20 | 2,946 | 1,661 | 1,285 | **43.6%** |\n\n## The problem\n\nEvery AI code editor today makes the model output old code to locate edits. Whether it's unified diffs, SEARCH/REPLACE blocks, or `apply_patch` — the model has to repeat back the lines it wants to change:\n\n```\n# Claude Code / Codex — model outputs old AND new code\n@@ -1,4 +1,6 @@\n def process(data):\n-    result = transform(data)\n-    return result\n+    try:\n+        result = transform(data)\n+        return result\n+    except Error as e:\n+        return {\"error\": str(e)}\n```\n\nYou're paying double: the model writes every old line (to say \"find this\") plus every new line (to say \"put this\"). On a 50-line function where you change 3 lines, that's 50 lines of output just for location, plus 3 lines of actual edit. **~94% of output tokens are wasted on telling the model where to put the code.**\n\n## How FastEdit works\n\nFastEdit eliminates location tokens entirely. Instead of making the model repeat old code, it uses two things:\n\n1. **AST awareness** — tree-sitter parses the file and finds the target function/class by name. No need to output old lines for location.\n2. **A fine-tuned 1.7B SLM** — when the edit is complex, a small merge model takes the original chunk (~35 lines) + edit snippet and produces the merged result.\n\n```python\n# FastEdit — model writes ONLY the change\nfastedit edit api.py --replace process --snippet '\n    try:\n        #...\n    except Error as e:\n        return {\"error\": str(e)}\n'\n```\n\n`--replace process` uses tree-sitter to find the function and auto-preserves its signature. `#...` (short form) tells the system to preserve untouched lines. The model never outputs old code — zero tokens spent on location, zero tokens spent on the signature.\n\n## The three edit modes\n\n| Mode | What happens | Tokens | Speed |\n|------|-------------|--------|-------|\n| `--after symbol` | Text insertion after the named symbol | 0 | Instant |\n| `--replace symbol` (deterministic) | Context anchors splice new lines in | 0 | Instant |\n| `--replace symbol` (model) | 1.7B SLM merges snippet into ~35-line chunk | ~40 | \u003c1s |\n\nThe system tries deterministic text-matching first. It classifies each snippet line as \"context\" (matches the original) or \"new\" (the edit), then splices new lines between the matched anchors. This handles **74% of real edits** with zero model calls.\n\nWhen deterministic matching can't resolve the edit (indent structure changes, full rewrites, \u003c2 matching lines), the 1.7B model takes over. It only ever sees a ~35-line function — never the whole file — so it's fast and accurate.\n\n## Install\n\n**Prerequisite:** [tldr](https://github.com/parcadei/tldr-code) must be on PATH (used for AST analysis).\n\n### Recommended — `uv tool` (handles the venv for you)\n\n```bash\n# Apple Silicon (local 1.7B model via MLX) + MCP server:\nuv tool install 'fastedits[mlx,mcp]'\n\n# GPU servers (vLLM backend) + MCP server:\nuv tool install 'fastedits[vllm,mcp]'\n\n# Generic (external OpenAI-compatible server) + MCP server:\nuv tool install 'fastedits[mcp]'\n\n# Download the 1.7B merge model (~3 GB, one-time):\nfastedit pull --model mlx-8bit    # Apple Silicon\nfastedit pull --model bf16        # Linux / GPU\n```\n\nThe CLI lands at `~/.local/bin/fastedit`. Upgrade later with `uv tool upgrade fastedits`.\n\nDrop the `mcp` extra if you only want the CLI. Drop `mlx` / `vllm` if you only want to point at an external LLM server.\n\n### Alternatives\n\n```bash\n# pipx (same idea, different tool):\npipx install 'fastedits[mlx,mcp]' \u0026\u0026 fastedit pull --model mlx-8bit\n\n# Plain venv:\npython3 -m venv ~/.venvs/fastedit\nsource ~/.venvs/fastedit/bin/activate\npip install 'fastedits[mlx,mcp]'\nfastedit pull --model mlx-8bit\n```\n\nAvoid `pip install fastedits` into a Homebrew / distro-managed Python — it will fail with `error: externally-managed-environment` (PEP 668).\n\n### Pointing at an external LLM server\n\n```bash\nFASTEDIT_BACKEND=llm FASTEDIT_LLM_API_BASE=http://localhost:1234/v1 fastedit edit ...\n```\n\nWorks with LM Studio, llama.cpp, Ollama (via OpenAI-compatible endpoint), vLLM, TGI, any OpenAI-API-compatible server.\n\n## CLI\n\n```bash\n# View file structure (functions, classes, line ranges)\nfastedit read src/app.py\n\n# Edit a function (AST-scoped merge)\n# replace= auto-preserves the signature; #... marks the rest of the body.\nfastedit edit src/app.py --replace handle_request --snippet '\n    validate(data)\n    #...\n    logger.info(\"done\")\n'\n\n# Insert new code after a symbol (0 tokens)\nfastedit edit src/app.py --after handle_request --snippet '\ndef health_check():\n    return {\"status\": \"ok\"}\n'\n\n# Batch edits to one file\nfastedit batch-edit src/app.py --edits '[\n  {\"snippet\": \"import redis\", \"after\": \"import json\"},\n  {\"snippet\": \"def cache_get(key): ...\", \"after\": \"connect\"}\n]'\n\n# Delete, move, rename (all instant, no model)\nfastedit delete src/app.py deprecated_handler\nfastedit move src/app.py helper_func --after main\nfastedit rename src/app.py old_name new_name\n\n# Undo last edit / show diff\nfastedit undo src/app.py\nfastedit diff src/app.py\n```\n\n## MCP server\n\nFastEdit runs as an MCP server for AI agents (Claude Code, Cursor, etc.). If you installed with the `mcp` extra above, the server binary is already on PATH as `fastedit-mcp`.\n\nAdd to Claude Code config (`~/.claude.json` or project `.mcp.json`):\n```json\n{\n  \"mcpServers\": {\n    \"fastedit\": {\n      \"command\": \"fastedit-mcp\",\n      \"type\": \"stdio\"\n    }\n  }\n}\n```\n\nNo hardcoded python paths, no `-m` invocation. Works wherever `fastedit` is on PATH.\n\n10 tools: `fast_edit`, `fast_batch_edit`, `fast_multi_edit`, `fast_read`, `fast_search`, `fast_diff`, `fast_delete`, `fast_move`, `fast_rename`, `fast_undo`\n\n### Auto-redirect Edit → fast_edit (optional)\n\nA PreToolUse hook intercepts Claude's built-in `Edit` tool and redirects to `fast_edit`. Zero tokens wasted — Edit never executes. Works on Mac, Linux, and Windows (PowerShell too).\n\nAdd to `.claude/settings.json` or your project `.claude.json`:\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Edit\",\n        \"hooks\": [{\"type\": \"command\", \"command\": \"fastedit-hook\"}]\n      }\n    ]\n  }\n}\n```\n\n`fastedit-hook` is installed automatically with `uv tool install fastedits` — no paths, no `python3` vs `python` issues.\n\n## The model\n\nFastEdit includes a fine-tuned 1.7B parameter model (Qwen2.5-Coder-1.5B architecture) trained specifically for code merging. It takes an original code chunk + edit snippet and produces the merged result.\n\nMost edits never reach the model:\n- `--after` is pure text insertion (0 tokens, instant)\n- `--replace` tries deterministic text matching first (0 tokens, instant)\n- Only when the snippet has complex structural changes does the 1.7B model activate\n\nThe model is scoped to ~35-line chunks via AST, so it runs in \u003c1s on Apple Silicon (MLX) or GPU (vLLM).\n\n## Accuracy\n\nTested across 22 structurally distinct edit patterns (73 cases):\n\n| Path | Accuracy | Tokens | Latency |\n|------|----------|--------|---------|\n| Deterministic (74% of edits) | 100% | 0 | \u003c1ms |\n| Model (26% of edits) | 92% | ~40 | ~500ms |\n| **Combined (production)** | **~98%** | **~10 avg** | **~130ms avg** |\n\nThe deterministic path handles the easy majority perfectly and for free. The model handles the complex minority. The AST scoping prevents the failure modes that plague whole-file approaches (ordering errors, content loss).\n\nPer-language model accuracy (156-example benchmark):\n\n| Language | Accuracy |\n|----------|----------|\n| Python, Java, Kotlin, C, PHP | 92% |\n| JavaScript, TypeScript, Rust, Swift | 85% |\n| Go, C++, Ruby | 77% |\n\n## How it compares\n\n|  | FastEdit | Claude Code / Codex | Aider SEARCH/REPLACE |\n|--|---------|-------------------|---------------------|\n| **How it locates the edit** | AST — names the symbol | Model outputs old lines | Model outputs SEARCH block |\n| **Tokens for location** | 0 | ~50% of output | ~50% of output |\n| **What the model sees** | ~35-line chunk | Entire file context | Entire file context |\n| **Failure mode** | Symbol not found (immediate, clear error) | Can't find old lines (silent misapply) | Can't find SEARCH block |\n| **Languages** | 13 | Any | Any |\n\n## Supported languages\n\nPython, JavaScript, TypeScript, Rust, Go, Java, C, C++, Ruby, Swift, Kotlin, C#, PHP\n\n## Environment variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `FASTEDIT_MODEL_PATH` | `~/.cache/fastedit/models/...` | Path to model |\n| `FASTEDIT_BACKEND` | `mlx` | Backend: `mlx` or `llm` |\n| `FASTEDIT_LLM_API_BASE` | `http://127.0.0.1:8000/v1` | LLM server URL (any OpenAI-compatible) |\n| `FASTEDIT_LLM_MODEL` | `fastedit` | Model name to send in API requests |\n| `FASTEDIT_LLM_API_KEY` | `not-needed` | API key (if server requires one) |\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparcadei%2Ffastedit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparcadei%2Ffastedit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparcadei%2Ffastedit/lists"}