You cannot press pause on development. That is the first thing to accept. Tickets keep arriving, customers expect shipments, and your existing code does not stop running just because you decided to document it. No engineering manager will greenlight a month-long freeze so the team can write the specification that should have existed from day one. OpenSpec was built for reality, not for greenfield fantasies. It works best when you bolt it onto what you already have, customers and all.
The goal here is not a rewrite. It is honest archaeology. You dig up what is actually running in production, describe it accurately, and let that description evolve as your code does. When your specification matches your system, you make life easier for the engineers who join next quarter and for the AI tools that now sit in your IDE. Here is how to do it without missing a single release.
Start With What You Actually Do
Open your repository and you will see folders named controllers, models, services, and utils. Those are technical layers, and they lie to you. They do not describe what your system does for the business. A folder full of JavaScript files does not explain how an order becomes a shipment. To retrofit OpenSpec, you need to think in capabilities.
Look for the stable business operations that would survive even if you rewrote the entire stack in a different language. In most product companies, these show up again and again: Orders, Billing, Inventory, Customers, and Notifications. Name five to eight of these core capabilities.
For each one, force yourself to answer five specific questions. What real-world problem does this capability solve? Where does the code actually live—one service, three microservices, or a legacy module no one wants to touch? What triggers it: a user click, a scheduled cron job, an inbound webhook? What data goes in and what data comes out? And finally, which other systems depend on it, meaning what breaks if this piece stops working?
Be brutally honest. If your "Customers" capability is smeared across a Rails monolith, a Node API, and an external CRM, write that down exactly. Your map has to look like the territory, not an architect's dream.
Write the Truth, Not the Wishlist
The most dangerous sentence in any documentation effort is, "While we're writing this down, we might as well fix it." Stop. You are not redesigning the checkout flow. You are describing the checkout flow that is charging real credit cards right now.
If placing an order triggers an immediate payment capture and then fires an email through a background worker, document that exact sequence. Do not insert an event queue you plan to add next quarter. Do not pretend the validation happens at the API edge if it actually lives deep inside a service class. Accuracy matters far more than aspiration.
Incorrect documentation is worse than none. It trains new hires to expect behavior that does not exist. It sends AI coding assistants down imaginary paths based on wishful thinking. When your spec matches production, you create a reliable baseline. Debugging gets faster because you stop guessing about the "intended" flow. Refactoring gets safer because you know the starting point is real.
Extract Contracts From Your APIs
Your API endpoints already enforce rules. They just keep them implicit. Retrofitting OpenSpec means pulling those rules into the open.
Start with inputs and validation. What does the endpoint actually accept? Document the types, the required fields, the maximum lengths, and the cross-field dependencies. Then describe the business behavior. Does this call create a record, trigger a side effect, or simply validate state against another service? Be specific.
Finally, catalog the responses. What does success return? What are the exact error codes and under what conditions do they appear? Do not write "returns an error." Write "returns 422 when the billing address is missing and 409 when the inventory was already reserved by another process." That level of precision turns a vague route into a contract that frontend teams, QA engineers, and automated tooling can trust.
Hunt Down the Hidden Rules
تكمن بعض أغلى أنواع المعرفة في نظامك داخل الفجوات. فهي مدفونة في الكتل الشرطية داخل فئات الخدمة (service classes)، أو مخبأة في مشغلات قواعد البيانات (database triggers)، أو مكتوبة في إجراءات مخزنة (stored procedures) لم يلمسها أحد منذ عامين. هذه هي قواعد العمل الخاصة بك، وعادة ما يتم اكتشافها مجددًا أثناء انقطاع الخدمة أو من خلال محاصرة المهندس الوحيد الذي يعمل هناك منذ البداية.
أخرج هذه القواعد إلى النور. ابدأ بتلك التي تعرفها بالفعل. الطلبات التي تتجاوز قيمة معينة تتطلب موافقة المدير قبل المضي قدمًا. حسابات المستخدمين غير النشطة لا يمكنها إنشاء طلبات جديدة. لا يُسمح باسترداد الأموال إلا قبل اكتمال عملية التسوية. اكتب كل قاعدة بجانب الميزة التي تحكمها، بلغة واضحة بما يكفي ليتمكن مدير المنتج من قراءتها دون الحاجة إلى مترجم.
عندما تقوم بمركزة هذه القواعد، فإنك تفعل أكثر من مجرد توثيقها؛ فأنت تكشف عن التكرار، وتظهر التعارضات، وتمنح الفريق بأكمله مكانًا واحدًا لمناقشة السياسات قبل أن يقوم شخص ما بتنفيذ تغيير من سطر واحد ينتهك بالخطأ قيدًا كنت قد نسيت وجوده.
رسم مخطط التمديدات
تعمل الأنظمة الحديثة بناءً على الأحداث (events). فالفعل في خدمة واحدة يمتد أثره عبر نصف درزن من الخدمات الأخرى قبل أن يصل أي شيء مرئي إلى المستخدم. أنت بحاجة إلى رسم مخطط لهذه التأثيرات المتسلسلة. قم برسم مسار التدفق من حدث إلى آخر لسير العمل الأساسي لديك. "إنشاء الطلب" يؤدي إلى "حجز المخزون"، والذي ينتظر "تأكيد الدفع". ارسم السلسلة الكاملة، حتى لو بدت بعض الروابط هشة أو تستخدم بروتوكولات مختلفة.
لا تتوقف عند حركة المرور الداخلية فقط. فالخدمات الخارجية هي جزء من نظامك سواء كنت تعاملها على هذا النحو أم لا. لكل عملية تكامل، سجل الغرض منها، وكيفية قيام تطبيقك بالمصادقة، وكيفية فشلها. هل تنتهي مهلة بوابة الدفع بعد ثلاثين ثانية وتعيد خطأ 500 عام؟ هل تعيد واجهة برمجة تطبيقات الشحن (shipping API) ملف JSON غير صالح في عطلات نهاية الأسبوع؟ هل يقوم مزود الهوية بإبطال رموز التحديث (refresh tokens) في وقت أبكر مما تدعي وثائقه الخاصة؟ تبدو هذه التفاصيل بسيطة
