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

Some of the most expensive knowledge in your system lives in the gaps. It is buried in conditional blocks inside service classes, tucked into database triggers, or written into stored procedures that no one has touched in two years. These are your business rules, and they are usually rediscovered during outages or by cornering the one engineer who has been there since the beginning.

Pull them into daylight. Start with the ones you already know. Orders above a certain value need manager approval before they proceed. Inactive user accounts cannot create new orders. Refunds are only permitted before settlement completes. Write each rule next to the capability it governs, in language clear enough that a product manager could read it without a translator.

When you centralize these rules, you do more than document them. You expose duplication. You reveal conflicts. And you give the entire team a single place to debate policy before someone commits a one-line change that accidentally violates a constraint you forgot existed.

Map the Plumbing

Modern systems run on events. An action in one service ripples through half a dozen others before anything visible reaches the user. You need to chart those ripples. Map the flow from one event to the next for your core workflows. Order created leads to inventory reserved, which waits for payment confirmed. Draw the full chain, even if some links feel fragile or use different protocols.

Do not stop at internal traffic. External services are part of your system whether you treat them that way or not. For each integration, record its purpose, how your application authenticates, and how it fails. Does the payment gateway timeout after thirty seconds and return a generic 500? Does the shipping API return malformed JSON on weekends? Does the identity provider revoke refresh tokens earlier than its own documentation claims? These details look trivial