דילוג לתוכן
תפריט

המוצר

פתרונות

אינטגרציות

מפתחים

שפה

המוצר

קובץ בינארי אחד, קובצי markdown, אינדקס נגזר

הוקים לוכדים את פעילות הסוכן. Markdown ב־git שומר את הדפים; SQLite שומר את אינדקס החיפוש ורשומות שקיימות רק במסד, כמו סשנים, העברות וחשבונות. גבה את שניהם. בהמשך מוצג המסלול מהלכידה לתדריך הבא.

קובץ בינארי אחד, תיקיית נתונים אחת.

SQLite מגיע בפנים, libgit2 הוא vendored וה-embedder כתוב ב-Rust טהור. אין sidecar, אין שרת מסד נתונים ואין תור שצריך להריץ. כל מה שהוא יודע נמצא בתיקייה אחת.

<data_dir>/

wiki/דפי markdown עם YAML frontmatter, ב-repository של git. מקור האמת.
db/memory.sqliteאינדקס חיפוש לצד סשנים, תצפיות, העברות, חשבונות ורשומות ביקורת שקיימים רק במסד. מצב WAL.
raw/מקטעי JSONL שעברו ניקוי ואינם משתנים, מסשנים מנוהלים של ai-memory run.
models/מודל ה-embeddings המקומי, all-MiniLM-L6-v2, בערך 87 MB ומקובע ב-SHA-256.
logs/פלט לוג יומי מתגלגל.
config.tomlנקרא פעם אחת בעלייה. לכל ערך יש override מסוג AI_MEMORY_*.

השרת מאזין כברירת מחדל על 127.0.0.1:49374. גיבוי הוא ai-memory backup, או git push של הוויקי יחד עם rsync של התיקייה.

מ-hook ועד התדריך הבא.

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

Hook

ניקוי

כותב יחיד

תצפיות

תצפיות

דף סשן

LLM אופציונלי

ויקי ב-git

תדריך

ויקי ב-git

Hook

רק השלב המקווקו צריך LLM. החץ החוזר הוא התדריך שמוזרק ב-SessionStart הבא.
  1. Hookאפס LLM

    ה-CLI של הסוכן מפעיל hook של מחזור החיים. זה fire and forget עם תקציב של 200 ms: hooks נייטיב שומרים את האירוע ב-spool מקומי, ותהליך עזר מנותק מעביר אותו הלאה. השרת עונה 202, או 429 כשהוא רווי.

  2. ניקויאפס LLM

    ה-router של /hook מסיר סודות ומגביל גדלים. זה הנתיב היחיד מטקסט לא מהימן אל ה-store.

  3. כותב יחידאפס LLM

    האירוע הנקי נכנס לתור אחד, ש-thread אחד מרוקן. אותו thread מחזיק בחיבור הכתיבה היחיד.

  4. תצפיותאפס LLM

    האירועים נשמרים ב-SQLite בתור audit trail תפעולי. זו השלכה מוגבלת של הסשן, ואף פעם לא תמלול מלא.

  5. סוף הסשןאפס LLM

    כללים, בלי מודל, הופכים את התצפיות ל-sessions/<id>.md ופותחים שורת Handoff לסוכן הבא, בטרנזקציה אחת.

  6. איחודLLM אופציונלי

    כשמוגדר ספק, LLM כותב מחדש את הסיכום או מפצל אותו ל-concepts/, decisions/, gotchas/ ו-procedures/. זה רץ מתוך תור עם ניסיונות חוזרים, מחוץ להשהיה של ה-hook.

  7. Commit ואינדוקסאפס LLM

    כל כתיבת דף היא אטומית (tmp, rename, fsync), נכנסת ב-commit ל-git, ומאונדקסת באותה טרנזקציית SQLite שבה נכתבת השורה שלה.

  8. שאילתה ותדריךאפס LLM

    memory_query מחפש באינדקס. ב-SessionStart הבא ה-hook מביא את ההעברה הפתוחה ותדריך מובנה לאותה תיקייה.

שתי שכבות, מקור אמת אחד.

אם הקבצים והאינדקס לא מסכימים, הקבצים מנצחים.

כותב

קובצי Markdown ב-git

מקור האמת

אינדקס SQLite

נגזר

קובצי Markdown ב-git

מעקב קבצים

אינדוקס מחדש

אינדקס SQLite

  • הקבצים הם האמת

    הדפים הם markdown עם YAML frontmatter תחת wiki///. אפשר לפתוח אותם ב-Obsidian, להריץ עליהם grep ולדחוף אותם ל-remote.

  • אינדקס הדפים הוא נתון נגזר

    Reindex בונה מחדש דפים, קישורים וחיפוש טקסט מתוך Markdown. הוא אינו משחזר סשנים, תצפיות, העברות, משתמשים, מפתחות או ביקורת שקיימים רק במסד.

  • הכתיבות שייכות לשרת

    כתיבות רגילות עוברות דרך שכבת הוויקי, שמעדכנת יחד את הקובץ, את היסטוריית ה-git ואת האינדקס.

  • watcher תופס את השאר

    עריכות מ-vim או מ-Obsidian נקלטות על ידי file watcher. diff מלא כל 30 שניות תופס אירועים שהוא פספס.

אחזור: חמישה ערוצים, דירוג אחד.

שאילתה

FTS5

ישויות

גרף

תצפיות

וקטורים

RRF k=60

סמכות

תוצאות

מסלול הווקטורים מקווקו כי החיפוש עובד גם בלעדיו.
  • טקסט מלא

    SQLite FTS5 על כותרות הדפים והגוף שלהם, עם סינון stopwords משאילתות חשופות.

  • התאמת ישויות

    אינדקס לקסיקלי של שמות מתוך entities ו-tags ב-frontmatter, משוקלל לפי שכיחות דפים הפוכה.

  • שכנים בגרף

    קפיצה אחת על טבלת הקישורים: wikilinks, קישורי markdown, קשתות מטופסות וקישורים בין פרויקטים. SQL רגיל, בלי מסד נתונים גרפי.

  • תצפיות

    טקסט מלא על התצפיות הגולמיות של הפרויקט. כל סשן מתאים מצביע פעם אחת, דרך התצפית הטובה ביותר שלו, עבור דף הסשן שלו, כך שפרט שלא הגיע לדף עדיין מוצא אותו. פעיל כברירת מחדל מאז 3.0.

  • וקטורים, אופציונלי

    דמיון קוסינוס על embeddings מהמודל המקומי שרץ בתוך התהליך. מופעל כברירת מחדל מאז 2.0, אף פעם לא חובה, ו-brute force בכוונה.

אחרי המיזוג

  • Reciprocal Rank Fusion עם k=60 ממזג את הערוצים לפי דירוג, כך שאף ערוץ לא צריך כיול של ציונים.
  • אחר כך מכפיל סמכות מוגבל מטה תחרויות צמודות לטובת כללים, החלטות, נהלים ומלכודות מתוחזקים. דפים אפיזודיים והיסטוריים נשארים בחיפוש, ושום דבר לא מוצא החוצה לגמרי.
  • LLM rerank אופציונלי: קריאה אחת לכל שאילתה, על עד 30 כותרות וקטעים. בכל כשל נשמר הסדר המקומי. עדיין אין reranker מקומי.
  • אם הדפים המקומפלים לא מחזירים כלום, חיפוש מוגבל בתצפיות הגולמיות מחזיר raw_hits.
  • הסינון קורה לפני הדירוג: kind, tag, tier וקידומת נתיב מצמצמים כל אחד מהזרמים, כך שדף נדיר לא נדחק החוצה על ידי דף נפוץ.
  • שני אותות אופציונליים מתחילים באפס: האחד מוריד את הסמכות של עמוד שיש עליו משוב פתוח של מיושן או שגוי, והשני מקדם עמוד שאותו סשן קרא או סימן כמועיל עבור שאילתה דומה. כתיבה מחדש מאפסת את שניהם.
  • מעבירים explain=true כדי לראות לכל תוצאה את הדירוג בכל ערוץ, את תרומות ה-RRF ואת המכפיל.

יפנית, קוריאנית וסינית

  • רצפים של Han, Kana ו־Hangul ללא מפרידי מילים דורשים התאמה לפי תווים. אינדקס נוסף של רצפים בני תו אחד ושני תווים נכתב באותה טרנזקציה של הדף.
  • זה אינדקס של SQLite, לא מודל. חיפוש ביפנית או בקוריאנית עדיין לא עולה קריאת API ולא embeddings.
  • טקסט לטיני ממשיך במסלול הרגיל, בלי שינוי. מאגר שעלה מגרסה ישנה ממלא את האינדקס החדש לפני שהוא מקבל תעבורה.

זמן: as_of

  • מעבירים תאריך ISO כדי לשאול מה הוויקי אמר על משהו באותו זמן.
  • הוא רושם רק את זמן ההזנה: מתי ai-memory למד עובדה ומתי החליף אותה, ואף פעם לא מתי היא הייתה נכונה בעולם.
  • הוא לא משחזר את הדירוג שחיפוש היה מחזיר באותו תאריך.
תקפות בזמן, בתיעוד

קשתות מטופסות (typed edges)

  • השדה relations: ב-frontmatter מקבל קבוצה סגורה: causes, fixes, contradicts. שגיאת הקלדה לא יכולה לייצר סוג חדש.
  • contradicts מזין את lint בלי LLM, ומדווח עד שמישהו מיישב את הסתירה.
  • בחיפוש הן מופיעות ב-explain בלבד: הן מצטרפות לגרף כקישורים רגילים ולא משפיעות על הדירוג, כי הבנצ'מרק לא נתן בסיס למשקל. memory_read_page יכול לעבור עליהן כדי להציג דפים קשורים.
קשתות מטופסות, בתיעוד

תופס אחד, כותב אחד.

שני כללים נושאים את רוב הנכונות: העברה אפשר לתפוס פעם אחת, ורק thread אחד כותב ל-SQLite.

העברות הן פרוטוקול

  • העברה היא רשומה מטופסת: סוכן מקור וסוכן יעד, פרויקט, cwd, סיכום, שאלות פתוחות, קבצים שנגעו בהם, צעדים הבאים.
  • הקבלה היא compare and set אטומי. סוכן שני שמבקש לא מקבל כלום.
  • ה-cwd מותאם לפי גבולות נתיב: /repo מכסה את /repo/api ואף פעם לא את /repo-other.
  • העברה ידנית גוברת על האוטומטית. הקבלה מפקיעה מועמדות אוטומטיות ישנות יותר באותה טרנזקציה.
  • בשרת משותף העברה שייכת לבעלים שלה, אלא אם היא נשלחה עם shared=true.

כלל הכותב היחיד, במדידה

כל הכתיבות עוברות דרך תור אחד, מוגבל ל-1024, אל thread אחד של מערכת ההפעלה. קריאות משתמשות ב-pool נפרד לקריאה בלבד. פרץ כתיבות מאט את היצרנים שלו, ואף כתיבה לא נזרקת.

  1. כותב 142 לשנייה23.9 ms
  2. 8 כותבים295 לשנייה3.4 ms
  3. 32 כותבים698 לשנייה1.43 ms
  4. 128 כותבים700 לשנייה1.43 ms
  • התקרה היא בערך 700 כתיבות בשנייה, והיא שטוחה מ-32 כותבים ומעלה. כותב אחד מוגבל על ידי fsync ולא על ידי ה-CPU.
  • נמדד על דיסק מקומי מהיר. volume ברשת או volume איטי יתנו מספרים נמוכים משמעותית.
  • הבדיקה מפעילה את ה-store ישירות ומדלגת על שכבת ה-HTTP שבחזית.
  • אפשר לשחזר עם cargo test -p ai-memory-store --test writer_throughput -- --ignored --nocapture.

דפי סשן ישנים מקבלים ציון, והקרים שבהם מפונים, מצומצמים או ממוזגים. איך זיכרון מתיישן.

הקוד, לפי crate.

עשרה crates של המוצר, לכל אחד תפקיד אחד ו-API מטופס, בלי תלויות מעגליות.

Crateאחריות
ai-memory-coreטיפוסי דומיין, שגיאות, מזהים. בלי IO.
ai-memory-storeSQLite, ה-actor של הכותב, pool הקוראים, חישובי הדעיכה.
ai-memory-wikiכתיבות markdown אטומיות, ה-file watcher, git.
ai-memory-mcpה-transport של MCP ו-router הכלים.
ai-memory-webתצוגות דפדפן ו־API של JSON לקריאה בלבד. פעולות חשבון ואישור פונות לנתיבים מאומתים.
ai-memory-hooksסכמות ה-payload, ה-sanitizer, הכניסה של /hook.
ai-memory-llmגבול האימות מול ספקים, ה-traits של LLM ושל embedder.
ai-memory-consolidateingest, lint, sweep וצינור השיפור האוטומטי.
ai-memory-workstreamמתאמים לקריאה בלבד לתמלולים נייטיב ולהרצות.
ai-memory-cliהקובץ הבינארי ai-memory ותתי-פקודות ה-HTTP הדקות שלו.

25 כלי MCP, מצומצמים בכוונה

ה-hooks עושים את הלכידה השגרתית, כך שסוכנים כמעט לא צריכים לקרוא לכלים האלה ידנית.

שליפה (7)

  • memory_query
  • memory_recent
  • memory_read_page
  • memory_read_session_observations
  • memory_briefing
  • memory_explore
  • memory_status

העברות (4)

  • memory_handoff_begin
  • memory_handoff_list
  • memory_handoff_accept
  • memory_handoff_cancel

הודעות בין פרויקטים (4)

  • memory_message_send
  • memory_message_list
  • memory_message_pop
  • memory_message_cancel

כתיבה ותחזוקה (10)

  • memory_write_page
  • memory_patch_page
  • memory_delete_page
  • memory_restore_page
  • memory_consolidate
  • memory_auto_improve
  • memory_feedback
  • memory_lint
  • memory_forget_sweep
  • memory_install_self_routing

ARCHITECTURE.md, עם כל 16 האינווריאנטיםהחלטות תכנון ואפשרויות שנדחו

שאלות ותשובות

איפה ai-memory שומר את הנתונים שלו?

בתיקיית נתונים אחת: repository git של דפי markdown תחת wiki/, אינדקס SQLite נגזר תחת db/, מקטעי רצף עבודה שעברו ניקוי תחת raw/, מודל ה-embeddings המקומי תחת models/, ולוגים.

האם ai-memory צריך LLM?

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

מה קורה אם אינדקס ה-SQLite אבד או נפגם?

Reindex בונה מחדש דפים, קישורים וחיפוש טקסט מתוך Markdown. הוא אינו משחזר סשנים, תצפיות, העברות, משתמשים, מפתחות או ביקורת שקיימים רק במסד.

איך האחזור מדרג תוצאות?

חמישה ערוצי מועמדים משתלבים: טקסט מלא ב-FTS5, התאמות ישויות, שכנים בגרף, תצפיות ווקטורים אופציונליים. Reciprocal Rank Fusion ב-k=60 משלב אותם, ואחריו מופעלת התאמה מוגבלת לפי סמכות המקור. rerank באמצעות LLM הוא אופציונלי.

בכמה כתיבות בשנייה הוא עומד?

ב-store נמדדו 42 כתיבות בשנייה עם כותב אחד, 295 עם 8, ותקרה של קרוב ל-700 מ-32 כותבים ומעלה. המספרים נמדדו על דיסק מקומי מהיר, והבדיקה מפעילה את ה-store ישירות בלי שכבת ה-HTTP שבחזית.

לקרוא את הקבצים שהוא כותב.

מתקינים, מריצים סשן אחד, ואז פותחים את תיקיית הוויקי בעורך.