filefunc — קובץ אחד, מושג אחד Image: AI generated

הבעיה

סוכני קוד AI (כמו Claude Code) מנווטים בקוד באמצעות grep לאיתור קבצים ו-read לפתיחתם. יחידת הקריאה היא הקובץ.

אבל מה קורה כשקובץ אחד מכיל 20 פונקציות?

צריך את type אחד בשם CrossError — read
→ 19 פונקציות מיותרות נלוות אליו
→ זיהום של ה-context

המחקר “Lost in the Middle” (Stanford, 2024) דיווח שכאשר מידע רלוונטי קבור באמצע ה-context, ביצועי LLM יורדים ביותר מ-30%. המחקר “Context Length Alone Hurts LLM Performance” (Amazon, 2025) מצא שטוקנים מיותרים — אפילו אם הם ריקים — גורמים לירידת ביצועים של 13.9% עד 85%.

מחקר GSM-DC (Yang et al., EMNLP 2025) הולך צעד נוסף. באמצעות ניסויים מבוקרים, הוא הוכיח שהקשר לא-רלוונטי לא רק “קובר” מידע שימושי — הוא פוגע באופן משמעותי הן בבחירת נתיבי ההיסק והן בדיוק האריתמטי של LLM. 19 הפונקציות המיותרות שנלוות אינן “בזבוז” — הן “הפרעה”.

המחקר הוכיח ש"context קצר יותר — טוב יותר". אולם לא היה כלי שמפרק קוד מבנית ומאפשר להכניס רק את מה שצריך.

filefunc ממלא את החלל הזה. זוהי מוסכמת מבנה קוד וכלי CLI לפיתוח אפליקציות Go — שירותי backend, כלי CLI, מחוללי קוד, ומאמתי SSOT.


עיקרון הליבה

קובץ אחד, מושג אחד. שם הקובץ = שם המושג.

בין אם מדובר ב-func, type, interface, או קבוצת const — הכלל זהה. כל שאר הכללים נגזרים מעיקרון יחיד זה.

# ללא filefunc
read utils.go → 20 funcs, 19 מיותרות. זיהום context.

# עם filefunc
read check_one_file_one_func.go → func אחד. בדיוק מה שצריך.

חשוב יותר לא לפתוח 290 קבצים מיותרים, מאשר לבחור 5–10 קבצים נכונים. מחקר השלמת קוד ASE 2025 (Yusuf et al.) דיווח ששליפה ברמת chunk משפרת את איכות השלמת הקוד ב-6% לעומת שליפה ברמת קובץ, וב-16% לעומת העדר הקשר. לא כמות ה-context קובעת את האיכות — אלא הגרנולריות.


האזרח הראשי הוא סוכן ה-AI

מבנה הקוד של filefunc מותאם לסוכן AI, לא לאדם.

סוכן AI מנווט עם grep, לא עם ls. בין אם יש 500 קבצים ובין אם 1000 — rg '//ff:func feature=validate' פעם אחת מספיק. ככל שיש יותר קבצים, כל קובץ קטן יותר, ויש פחות רעש בכל read — וזה דווקא יתרון. Cao et al. (2026) דיווחו על תוצאות ניסוי המראות שסוכני קידוד מעבדים קורפוסים של 3 טריליון טוקנים באמצעות ניווט במערכת קבצים (ls, grep, read), ועולים על מודלים קיימים עם הקשר ארוך ב-17.3%. יחידת הניווט של סוכן ה-AI היא הקובץ.

השאלה “האם לא יצטברו יותר מדי קבצים?” היא לגיטימית — עבור בני אדם. אבל אי-הנוחות האנושית נפתרת בשכבת התצוגה (כמו הרחבות VSCode). מבנה filefunc לא מתפשר לטובת נוחות האדם.


ניווט שונה לחלוטין

גישה מסורתית

בקשת משתמש
→ ls, find כי לא יודעים מה יש
→ פותחים קבצים כדי להבין מבנה
→ grep נוסף לאיתור קבצים קשורים
→ פותחים קובץ — 20 funcs, רובם מיותרים
→ עלות ניווט > זמן עבודה בפועל

עם filefunc

בקשת משתמש + codebook
→ קוראים את ה-codebook ומנסחים מיד query ל-grep
→ read של 20–30 קבצים (כל אחד מושג אחד, הכל context תקף)
→ עבודה

אם כל 30 הקבצים שקראת הם context תקף — 30 קבצים זה לא בעיה. הבעיה היא לקרוא קובץ אחד ולקבל 30 קבצים שווי-ערך של רעש.


ה-Codebook

ה-codebook הוא המרכיב החשוב ביותר בתכנון filefunc. הוא מקדים את כללי ה-annotation. codebook מתוכנן היטב מוביל ל-query מדויק ב-grep, ו-grep מדויק מוביל לרשימת read נקייה.

# codebook.yaml
required:
  feature: [validate, annotate, chain, parse, codebook, report, cli]
  type: [command, rule, parser, walker, model, formatter, loader, util]

optional:
  pattern: [error-collection, file-visitor, rule-registry]
  level: [error, warning, info]

מפתחות required חייבים להופיע בכל annotation מסוג //ff:func ו-//ff:type. זה מבטיח אמינות ב-grep — אין ערכים חסרים תחת מפתחות required. מפתחות optional משמשים רק כשרלוונטי.

ה-codebook הוא מפת הפרויקט של סוכן ה-AI. ללא codebook, הניווט מתחיל בלי מילון. עם codebook, ניתן לשלוח מיד query מדויק כמו feature=validate, type=rule — ללא שלב חיפוש.

שימוש בערך שלא מופיע ב-codebook הוא ERROR. נרמול המילון דרך ה-codebook חושף feature חסר, type כפול, וסיווג עמום. רק כשרואים את הפרצה — אפשר לנהל. גם ה-codebook עצמו עובר אימות — לפחות מפתח required אחד, ללא כפילויות, רק אותיות קטנות ומקפים.


Metadata Annotation

כל קובץ מקבל annotation בראשו. כדי שניתן יהיה להבין את המטא-דאטה מכמה שורות בלבד, ללא read של כל ה-body.

//ff:func feature=validate type=rule control=sequence
//ff:what F1: validates one func per file
//ff:why Primary citizen is AI agent. 1 file 1 concept prevents context pollution.
//ff:checked llm=gpt-oss:20b hash=a3f8c1d2
func CheckOneFileOneFunc(gf *model.GoFile) []model.Violation {
Annotationתוכןחובה
//ff:funcמטא-דאטה לקובץ func: feature, type, control ועודחובה בקבצי func
//ff:typeמטא-דאטה לקובץ type: feature, type ועודחובה בקבצי type
//ff:whatהסבר בשורה אחת — מה הפונקציה/הטיפוס עושהחובה
//ff:whyלמה הוחלט כך — הנימוק מאחורי ההחלטהאופציונלי
//ff:checkedחתימת אימות LLM (נוצרת אוטומטית על-ידי llmc)אוטומטי

הפורמט הוא //ff:key key1=value1 key2=value2. ניתן לחיפוש מיידי עם grep/ripgrep, ומובנה כ-key-value לפרסור על-ידי כלים. זהו אותו דפוס של //go:generate ו-//go:embed ב-Go.

control — 1 func, 1 control

control= חובה בכל קובץ func. הערך הוא אחד מתוך שלושה:

controlמשמעותהגבלת depth
sequenceביצוע רציף2
selectionהסתעפות (switch)2
iterationלולאהdimension + 1

מבוסס על משפט Böhm-Jacopini (1966): כל תוכנית היא צירוף של sequence, selection ו-iteration. filefunc מאכף זאת ברמת הפונקציה — פונקציה אחת, זרימת בקרה אחת.

פונקציה עם control=iteration חייבת לכלול גם dimension= — ממד הנתונים שעליהם עוברים. dimension=1 הוא רשימה שטוחה (depth ≤ 2), dimension ≥ 2 דורש מיבנים מוגדרים (struct/interface).

filefunc מאמת גם את ההתאמה בין control לקוד בפועל. אם control=selection אבל אין switch, או control=sequence אבל יש switch או loop — זה ERROR.


פייפליין ניווט LLM

ה-annotation פועל כאינדקס חיפוש, ללא תשתית כבדה כמו vector embedding.

1. צמצום מבני (ללא LLM, grep)
   בניית query על בסיס codebook
   → חילוץ 20–30 קבצים מועמדים

2. שיפוט מטא (ללא LLM או LLM זעיר)
   read רק של annotation בראש כל קובץ
   → צמצום ל-5–10 על בסיס name/input/output/what

3. עבודה מדויקת (LLM גדול, context מינימלי)
   full read רק של 5–10 קבצים
   → עריכה/יצירת קוד

ככל שהשלב מתקדם, ה-context מצטמצם. כשה-LLM הגדול נכנס לפעולה — נשארו רק הקבצים שבאמת נחוצים.


CLI

validate — אימות כללי מבנה הקוד

filefunc validate                    # תיקייה נוכחית
filefunc validate /path/to/project   # שורש פרויקט מפורש
filefunc validate --format json

שורש הפרויקט צריך לכלול go.mod ו-codebook.yaml. קריאה בלבד. exit code 1 בעת הפרה.

chain — מעקב אחר יחסי קריאה

filefunc chain func RunAll              # קרוב 1 (ברירת מחדל)
filefunc chain func RunAll --chon 2     # קרוב 2 (כולל פונקציות שנקראות יחד)
filefunc chain func RunAll --chon 3     # קרוב 3 (מקסימום)
filefunc chain func RunAll --child-depth 3   # רק קריאות ילד
filefunc chain func RunAll --parent-depth 3  # רק קוראים הורה
filefunc chain feature validate         # feature שלם

ניתוח AST בזמן אמת. --chon הוא מרחק הקשר. קרוב 1 הוא קריאה/נקרא ישיר, קרוב 2 כולל פונקציות שנקראות יחד.

go callgraph הקיים מנתח את כל הקריאות סטטית ומייצר אלפי nodes. chain עוקב רק בתוך אותו feature. ה-feature מה-codebook הוא רמת הזום.

llmc — אימות LLM

filefunc llmc                           # תיקייה נוכחית
filefunc llmc --model qwen3:8b
filefunc llmc --threshold 0.9

מאמת שה-//ff:what מתאים ל-func body באמצעות LLM מקומי (ollama). ציון 0.0–1.0, סף ברירת מחדל 0.8. אם עובר, רושם אוטומטית //ff:checked llm=שם-מודל hash=hash. שינוי ב-body משנה את ה-hash ודורש אימות מחדש.

זוהי פתרון ל-annotation drift — //ff:what הוא טקסט חופשי שלא ניתן לאמת מכנית — באמצעות LLM קטן. האפשרות קיימת כי 1 file 1 func מבטיח התאמה 1:1 ברמת הקובץ.


כללים

כללי מבנה קובץ

כללבעת הפרה
func אחד לקובץ (שם הקובץ = שם הפונקציה)ERROR
type אחד לקובץ (שם הקובץ = שם הטיפוס)ERROR
method: 1 file 1 methodERROR
init() לא עומד לבד (חייב עם var או func)ERROR
_test.go מאפשר func מרובותחריג
const שהם יחידה סמנטית מותרים באותו קובץחריג

כללי איכות קוד

כללבעת הפרה
עומק הקינון: sequence=2, selection=2, iteration=dimension+1ERROR
מקסימום 1000 שורות לפונקציהERROR
המלצה: sequence/iteration 100 שורות, selection 300 שורותWARNING

עומק הקינון תלוי בסוג ה-control. sequence ו-selection — depth 2. iteration — dimension + 1. עבור dimension=1 (רשימה שטוחה) זה depth 2, עבור dimension=2 (מבנה מקונן) זה depth 3. בשילוב עם דפוס early return של Go, רוב הקוד נכנס בתוך המגבלות.

ל-selection (switch) נוטה להיות case ארוכים, ולכן מגבלת השורות המומלצת היא 300.


.ffignore

קובץ .ffignore בשורש הפרויקט מוציא נתיבים מכל פקודות filefunc. תחביר זהה ל-.gitignore.

vendor/
*.pb.go
*_gen.go
internal/legacy/

מיועד להוצאת קוד שלא ניתן לאכוף עליו את כללי filefunc — כמו קוד שנוצר אוטומטית (protobuf, קוד-גן) או קוד vendor חיצוני.


שילוב עם whyso

כיוון ש-func = file, היסטוריית שינויים ברמת פונקציה נופלת בדיוק על היסטוריה ברמת קובץ.

whyso history check_ssac_openapi.go   # היסטוריית שינויים של פונקציית CheckSSaCOpenAPI

כשקובץ מכיל כמה פונקציות, צריך לחפש ב-diff כדי לדעת איזו פונקציה השתנתה. עם filefunc, שינוי בקובץ = שינוי בפונקציה. עלות מעקב אפסית.

זיהוי coupling סמוי

whyso coupling check_ssac_openapi.go

פונקציות שהשתנו יחד באותה בקשה:
  check_response_fields.go  8 פעמים
  check_err_status.go       5 פעמים
  types.go                  4 פעמים

אם קובץ מופיע שוב ושוב בסטטיסטיקת coupling ללא קשר מפורש — זה סימן לתלות נסתרת. ייתכן שמדובר בפונקציות שמממשות אותו כלל עסקי מזוויות שונות, שמתאמות format בשתיקה ללא interface, או שבאגים בהן תמיד מופיעים יחד.


למה דווקא Go?

מחוץ ל-Go, מבנה filefunc קשה ליישום. gofmt מאכף פורמט קוד, early return הוא מוסכמה, אין exceptions, ו-package = directory. הרחבה לשפות אחרות דורשת אסטרטגיית כפייה מבנית ברמת gofmt — וזה מחוץ לתחום של filefunc.

גם הייעוד ברור: שירותי backend, כלי CLI, מחוללי קוד, מאמתי SSOT. ספריות אלגוריתמיות, תכנות מערכת ברמה נמוכה, ו-hot path קריטי לביצועים — אלה לא היעד.


סיכום

מבנה הקוד בעידן ה-LLM צריך להיות מותאם ליעילות הניווט של AI, לא לנוחות הניווט האנושית. filefunc הוא הצעד הראשון במעבר הזה.

קובץ אחד, מושג אחד. נרמול מילון דרך codebook, צירוף מטא-דאטה דרך annotation, ומציאת הקובץ המדויק עם grep אחד. אין קוד מיותר שנסחב עם כל read. זיהום ה-context נחסם על-ידי מבנה הקוד עצמו.

קוד: github.com/park-jun-woo/filefunc


מקורות

  • Nelson F. Liu, Kevin Lin, John Hewitt, Ashwin Paranjape, Michele Bevilacqua, Fabio Petroni, Percy Liang (2024). “Lost in the Middle: How Language Models Use Long Contexts.” Transactions of the Association for Computational Linguistics, vol. 12. Link
  • Yufeng Du, Minyang Tian et al. (2025). “Context Length Alone Hurts LLM Performance Despite Perfect Retrieval.” Findings of EMNLP 2025. Link
  • Minglai Yang, Ethan Huang, Liang Zhang, Mihai Surdeanu, William Yang Wang, Liangming Pan (2025). “How Is LLM Reasoning Distracted by Irrelevant Context?” EMNLP 2025 Main Conference. Link
  • Uswat Yusuf, Genevieve Caumartin, Diego Elias Costa (2025). “Beyond More Context: How Granularity and Order Drive Code Completion Quality.” ASE 2025. Link
  • Weili Cao, Xunjian Yin, Bhuwan Dhingra, Shuyan Zhou (2026). “Coding Agents are Effective Long-Context Processors.” arXiv preprint. Link
  • Han Li, Letian Zhu, Bohan Zhang et al. (2026). “ContextBench: A Benchmark for Context Retrieval in Coding Agents.” arXiv preprint. Link
  • Kishan Maharaj et al. (2026). “Robustness and Reasoning Fidelity of Large Language Models in Long-Context Code Question Answering.” arXiv preprint. Link
  • Carlos E. Jimenez, John Yang, Alexander Wettig, Shunyu Yao, Kexin Pei, Ofir Press, Karthik R. Narasimhan (2024). “SWE-bench: Can Language Models Resolve Real-World GitHub Issues?” ICLR 2024 (Oral). Link
  • Corrado Bohm, Giuseppe Jacopini (1966). “Flow Diagrams, Turing Machines, and Languages with Only Two Formation Rules.” Communications of the ACM, vol. 9, no. 5. Link
  • David L. Parnas (1972). “On the Criteria to Be Used in Decomposing Systems into Modules.” Communications of the ACM, vol. 15, no. 12. Link

קשור: Ratchet Pattern — איך לגרום לסוכן לסיים את העבודה — הדפוס מאחורי filefunc. הרצה חד-כיוונית מונחית verifier.

קשור: IQ של מודל חשוב פחות מטופולוגיית הפידבק — למה מבנה הפידבק קובע תוצאות יותר מביצועי המודל.

יומן שינויים

  • 2026-03-16: מהדורה ראשונה