
git blameيُخبرك من غيّر، ومتى، وماذا. أما whyso فيُخبرك لماذا غُيِّر.
المشكلة
حين تريد أن تعرف لماذا سطر من الكود يبدو هكذا، كل ما بوسعك فعله هو النظر في git blame وقراءة رسائل الـ commit.
$ git blame internal/handler/page.go
a3f1b2c (parkjunwoo 2026-03-08) func CreatePage(c *gin.Context) {
ستعرف من غيّر، ومتى، وماذا. لكنك لن تعرف لماذا غيّر.
قد تقول: أليس كافياً أن تكتب السبب في رسالة الـ commit؟ الواقع يقول:
fix: update handler
refactor: clean up
wip
كتابة رسائل commit جيدة مسألة انضباط. مهما وضع الفريق من اتفاقيات، نادراً ما يفكر أحد في الساعة الثالثة صباحاً وهو يُصلح خطأً بالقول: “ينبغي أن أوثّق سياق هذا التغيير ومبرراته في رسالة commit بعناية”.
غير أن عصر البرمجة بالذكاء الاصطناعي يُغيّر المعادلة. سبب التغيير مسجَّل أصلاً.
بيانات جلسات Claude Code
يحفظ Claude Code جميع المحادثات في ملفات JSONL تحت ~/.claude/projects/. يحتوي كل سجل على رسائل المستخدم، وردود الذكاء الاصطناعي، واستدعاءات tool_use (Write وEdit وBash)، فضلاً عن سلسلة parentUuid التي تربط هذه العناصر بعضها ببعض.
المستخدم: "ابدأ في تنفيذ أمر whyso validate"
→ AI: Write internal/crosscheck/crosscheck.go
→ AI: Edit internal/crosscheck/crosscheck.go
→ AI: "إنشاء حزمة crosscheck الأولية — التحقق من تطابق operationId بين SSaC وOpenAPI"
سبب إنشاء الملف وسبب تعديله محفوظان في المحادثة ذاتها. هذه البيانات أغنى من رسائل commit، ولا تحتاج إلى كتابة متعمدة — إذا جرت المحادثة، سُجِّل كل شيء تلقائياً.
whyso يُحلّل هذه البيانات ويستخرج سجل التغييرات لكل ملف.
سيرة الملف كاملةً أمامك
file: internal/crosscheck/crosscheck.go
created: 2026-03-08T14:23:01Z
history:
- timestamp: 2026-03-08T14:23:01Z
session: 09351222-d7be-41fe-994f-87c2d7067e5d
user_request: "ابدأ في تنفيذ أمر whyso validate"
answer: "إنشاء حزمة crosscheck الأولية — التحقق من تطابق operationId بين SSaC وOpenAPI"
tool: Write
- timestamp: 2026-03-09T10:15:33Z
session: 4e9b4e5e-3a50-43f2-be6e-e5db228ecc3b
user_request: "أضف التحقق من وجود عمود x-sort في DDL"
answer: "إضافة التحقق المتقاطع لأعمدة x-sort/x-filter مع DDL"
tool: Edit
- timestamp: 2026-03-10T09:41:22Z
session: b2e43b4f-cb21-4286-975d-1eb9de8a16c0
user_request: "أضف أيضاً التحقق المتقاطع لمواصفات Func"
answer: "إضافة التحقق المتقاطع لعدد وأنواع وسيطات @call مقابل مواصفات Func"
tool: Edit
لماذا أُنشئ الملف، وكيف تطوّر استجابةً لأي طلب — ترى السيرة الكاملة لكل ملف.
لماذا نحتاج إلى هذا
الفراغ في مراجعة الكود
عند مراجعة pull request، تصل إلى لحظة تسأل فيها: “لماذا جرى هذا التغيير؟”. إذا لم يكن السبب في رسالة الـ commit، يجب أن تسأل كاتبه. وإن لم يتذكر، عليك إعادة قراءة الكود واستنتاج السبب.
في بيئة البرمجة بالذكاء الاصطناعي، الإجابة موجودة في بيانات الجلسة. whyso يستخرج هذه الإجابة.
الانضمام إلى الفريق
أسرع طريقة لعضو فريق جديد لفهم قاعدة الكود هي معرفة “لماذا أصبح الكود هكذا”. git log قائمة زمنية للتغييرات، والوثائق لقطة للحالة الراهنة. أما سجل whyso لكل ملف فيكشف ما بينهما — سلسلة النوايا.
التوثيق الذاتي
حتى حين تعمل بمفردك، تأتي لحظة لا تتذكر فيها لماذا بنيت الشيء هكذا قبل ثلاثة أشهر. whyso يستعيد المحادثة التي جرت بينك وبين الذكاء الاصطناعي في الماضي. السياق الذي لم تكتبه في رسالة الـ commit موجود هناك.
العلاقة مع git blame
whyso لا يحل محل git blame، بل يُكمله.
| git blame | whyso | |
|---|---|---|
| من | O | — |
| متى | O | O |
| ماذا غُيِّر | O (سطراً بسطر) | O (وحدة tool_use) |
| لماذا غُيِّر | △ (رسالة commit) | O (طلب المستخدم + شرح الذكاء الاصطناعي) |
| مصدر البيانات | سجل git | جلسات Claude Code |
إذا كان git blame “السجل الرسمي” المبني على الـ commits، فإن whyso هو “سجل العمل” المبني على المحادثات. السياق الذي لم يُكتب في السجل الرسمي يبقى في سجل العمل.
بنية يقرأ فيها الذكاء الاصطناعي سجلاته
أكثر حالات استخدام whyso إثارةً للاهتمام هي أن الذكاء الاصطناعي نفسه هو من يقرأ هذه السجلات.
Claude Code ينسى كل شيء حين تنتهي الجلسة. حين تفتح المشروع ذاته في جلسة جديدة، لا توجد أي معلومة عن سبب البناء بذلك الأسلوب بالأمس، ولا عن الخيارات التي جرى تقييمها وإلغاؤها، ولا عن السياق الذي طلب فيه المستخدم ذلك — كل شيء اختفى. لا يبقى إلا قراءة الكود والاستنتاج.
تخيّل أنك تضيف سطراً واحداً إلى CLAUDE.md:
قبل تعديل أي ملف، شغّل `whyso history <file>` حتماً. إذا وجدت سجلاً، اقرأه قبل التعديل.
ما يُغيّره هذا السطر الواحد:
معرفة التغييرات التي لا ينبغي التراجع عنها
تقرأ الملف استعداداً لتعديله فترى كوداً يبدو غريباً. من النظر إلى الحالة الراهنة فحسب، قد تميل إلى “تصحيحه”. لكن إذا كان سجل whyso يقول “طلب المستخدم صراحةً هذا البناء، والسبب ليس الأداء بل سهولة القراءة”، فلن تقربه.
تجنّب اقتراح خيارات سبق رفضها
في الجلسة السابقة جرى الحوار: “هل نجرّب الأسلوب A؟” ثم “لا، لنذهب نحو B”. الذكاء الاصطناعي في الجلسة الجديدة لا يعرف هذا، فيقترح A مجدداً — أمر مزعج للمستخدم. مع whyso، يعرف الذكاء الاصطناعي ما سبق تقييمه ورفضه.
استمرارية سياق العمل المتصل
حين تقول “أكمل عملية إعادة الهيكلة من أمس”، يضطر الذكاء الاصطناعي الآن إلى قراءة الـ diff واستنتاج ما جرى. مع سجل whyso، يقرأ طلبات المستخدم من جلسة الأمس ومبررات قرارات الذكاء الاصطناعي مباشرةً. يصبح العمل المتواصل مبنياً على الوقائع لا على الاستنتاج.
تراكم السجلات عبر الجلسات
بهذه البنية، يتراكم سجل whyso مع كل جلسة. سبب التعديل في الجلسة الحالية يُنقل إلى الذكاء الاصطناعي في الجلسة القادمة. مشكلة غياب الذاكرة بين الجلسات تُحل على مستوى كل ملف — دون الحاجة إلى نظام ذاكرة منفصل.
ما يُسجَّل في whyso هو ما فعله الذكاء الاصطناعي. لكن الذكاء الاصطناعي لا يتذكره. السجل الذي صنعه هو أشد ما يحتاجه هو نفسه. هذا هو الجانب الفريد لـ whyso حين يقترن بأدوات البرمجة بالذكاء الاصطناعي.
بالنسبة للإنسان، whyso هو “أداة تترك رسائل commit جيدة تلقائياً”. أما بالنسبة للذكاء الاصطناعي، فwhyso هو ذاكرة تتخطى الجلسات.
طريقة الاستخدام
التثبيت
go install github.com/park-jun-woo/whyso/cmd/whyso@latest
استعراض سجل الملف
# ملف واحد
whyso history README.md
# دليل كامل
whyso history internal/ --all
# إخراج يعكس بنية الملفات
whyso history . --all --output .file-histories/
# تنسيق JSON
whyso history README.md --format json
قائمة الجلسات
whyso sessions
آلية العمل
تتبع سلسلة parentUuid عكساً
كل سجل في JSONL مرتبط بـ uuid وparentUuid. بتتبع سلسلة parentUuid عكساً من tool_use الذي عدّل الملف، يمكن الوصول إلى الطلب الأصلي للمستخدم الذي أطلق هذا التعديل.
user message (uuid: A) ← "أضف التحقق من وجود عمود x-sort في DDL"
→ assistant tool_use (parentUuid: A)
→ tool_result (parentUuid: B)
→ assistant Edit (parentUuid: C) ← سبب هذا التعديل = A
بما أن رسائل tool_result تتخلل السلسلة، يكفي استخراج الرسائل التي type == "user" ومحتواها نص لإيجاد طلب المستخدم الفعلي.
قرارات التصميم
تتبع Write/Edit فقط. استدعاءات Write وEdit في Claude Code تتضمن مسار الملف ومحتوى التغيير صراحةً. معالجة الملفات في أوامر Bash (مثل rm وmv وcp) تُكتشف بأساليب استدلالية، لكن Write/Edit هما الهدف الرئيسي للتتبع. بما أن Claude Code مُصمَّم لاستخدام Write/Edit عند تعديل الملفات، فإن هذين الأداتين كافيتان لالتقاط معظم التغييرات.
تضمين الوكلاء الفرعيين. حين يُعالج Claude Code مهاماً معقدة، يُنشئ أحياناً وكلاء فرعيين. جلسات هؤلاء الوكلاء تُخزَّن داخل دليل الجلسة الأم. whyso يُحلّل هذه الجلسات الفرعية أيضاً لبناء سجل كامل.
التحديث التدريجي. عند الإخراج إلى دليل عبر خيار --output، تُتخطى الجلسات التي سبق تحليلها. حتى لو تجاوز عدد الجلسات المئات، لا يُعاد تحليل كل شيء من البداية في كل مرة.
الأرقام
نتائج تتبع whyso لمشروع whyso ذاته أثناء تطويره:
| البند | القيمة |
|---|---|
| عدد الجلسات | 17 |
| استدعاءات Write | 660 |
| استدعاءات Edit | 1,415 |
| معالجة ملفات بـ Bash | 206 |
| عدد الملفات الفريدة المُعدَّلة | 480 |
جرى استخراج سجل تغييرات 480 ملفاً من 17 جلسة. لكل ملف تسجيل بـ"لماذا أُنشئ ولماذا تغيّر".
القيود
- مخصص لـ Claude Code فقط. بيانات جلسات أدوات البرمجة بالذكاء الاصطناعي الأخرى تختلف في تنسيقها. حالياً يدعم whyso تنسيق JSONL الخاص بـ Claude Code فقط.
- تتبع الملفات النصية فقط. استدعاءات Write/Edit تستهدف الملفات النصية. التغييرات في الصور والملفات الثنائية لا تُتتبع.
- بيانات الجلسة يجب أن تكون محلية. يجب أن تكون ملفات الجلسة موجودة في
~/.claude/projects/. إذا حُذفت أو جرى العمل على جهاز آخر، فتلك السجلات غير متاحة.
خلاصة
في عصر كتابة الكود مع الذكاء الاصطناعي، لم يعد سبب التغيير رهيناً برسائل الـ commit وحدها. المحادثة ذاتها هي السجل، ويمكن استخراج سجل التغييرات لكل ملف من ذلك السجل تلقائياً.
إذا كان git blame يُخبرك “من غيّر ومتى وماذا”، فإن whyso يُخبرك “لماذا غُيِّر”.